*.class
sdk/java/log
tmp
+sdk/cli/binstubs/
+sdk/cwl/arvados_cwl/_version.py
+services/api/config/arvados-clients.yml
+*#*
+.DS_Store
## Development
[![Build Status](https://ci.curoverse.com/buildStatus/icon?job=run-tests)](https://ci.curoverse.com/job/run-tests/)
+[![Go Report Card](https://goreportcard.com/badge/github.com/curoverse/arvados)](https://goreportcard.com/report/github.com/curoverse/arvados)
The Arvados public bug tracker is located at https://dev.arvados.org/projects/arvados/issues
source 'https://rubygems.org'
-gem 'rails', '~> 4.1.0'
+gem 'rails', '~> 4.1'
gem 'arvados', '>= 0.1.20150511150219'
gem 'activerecord-nulldb-adapter'
# in production environments by default.
group :assets do
gem 'sass-rails'
- gem 'uglifier', '>= 1.0.3'
+ gem 'uglifier', '~> 2.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', :platforms => :ruby
end
group :test, :diagnostics, :performance do
- gem 'minitest', '>= 5.0.0'
+ gem 'minitest', '~> 5.0'
gem 'selenium-webdriver'
gem 'capybara'
gem 'poltergeist'
deep_merge (1.0.1)
docile (1.1.5)
erubis (2.7.0)
- execjs (2.2.2)
+ execjs (2.7.0)
extlib (0.9.16)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
signet (~> 0.7)
headless (1.0.2)
highline (1.6.21)
- httpclient (2.6.0.1)
+ httpclient (2.8.2.4)
i18n (0.7.0)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
metaclass (~> 0.0.1)
morrisjs-rails (0.5.1)
railties (> 3.1, < 5)
- multi_json (1.12.0)
+ multi_json (1.12.1)
multipart-post (2.0.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
- uglifier (2.7.0)
+ uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
websocket (1.2.2)
less-rails
lograge
logstash-event
- minitest (>= 5.0.0)
+ minitest (~> 5.0)
mocha
morrisjs-rails
multi_json
piwik_analytics
poltergeist
rack-mini-profiler
- rails (~> 4.1.0)
+ rails (~> 4.1)
rails-perftest
raphael-rails
ruby-debug-passenger
sshkey
themes_for_rails!
therubyracer
- uglifier (>= 1.0.3)
+ uglifier (~> 2.0)
wiselinks
BUNDLED WITH
- 1.12.1
+ 1.13.2
$(document).
- on('click', '.component-detail-panel', function(event) {
- var href = $($(event.target).attr('href'));
- if ($(href).attr("class").split(' ').indexOf("in") == -1) {
- return; // collapsed; nothing more to do
- }
-
+ on('click', '.component-detail-panel', function(event) {
+ var href = $($(event.target).attr('href'));
+ if ($(href).hasClass("in")) {
var content_div = href.find('.work-unit-component-detail-body');
content_div.html('<div class="spinner spinner-32px col-sm-1"></div>');
var content_url = href.attr('content-url');
var action_data = href.attr('action-data');
$.ajax(content_url, {dataType: 'html', type: 'POST', data: {action_data: action_data}}).
- done(function(data, status, jqxhr) {
- content_div.html(data);
- }).fail(function(jqxhr, status, error) {
- content_div.html(error);
- });
- });
+ done(function(data, status, jqxhr) {
+ content_div.html(data);
+ }).fail(function(jqxhr, status, error) {
+ content_div.html(error);
+ });
+ }
+ });
# from the top three levels.
# That is: get toplevel projects under home, get subprojects of
# these projects, and so on until we hit the limit.
- def my_wanted_projects user, page_size=100
+ def my_wanted_projects(user, page_size=100)
return @my_wanted_projects if @my_wanted_projects
from_top = []
break if current_level.results.size == 0
@too_many_projects = true if current_level.items_available > current_level.results.size
from_top.concat current_level.results
- uuids = current_level.results.collect { |x| x.uuid }
+ uuids = current_level.results.collect(&:uuid)
depth += 1
if depth >= 3
@reached_level_limit = true
end
helper_method :my_wanted_projects_tree
- def my_wanted_projects_tree user, page_size=100
- build_my_wanted_projects_tree user, page_size
+ def my_wanted_projects_tree(user, page_size=100)
+ build_my_wanted_projects_tree(user, page_size)
[@my_wanted_projects_tree, @too_many_projects, @reached_level_limit]
end
- def build_my_wanted_projects_tree user, page_size=100
+ def build_my_wanted_projects_tree(user, page_size=100)
return @my_wanted_projects_tree if @my_wanted_projects_tree
parent_of = {user.uuid => 'me'}
end
end
+ def copy
+ src = @object
+
+ @object = ContainerRequest.new
+
+ @object.command = src.command
+ @object.container_image = src.container_image
+ @object.cwd = src.cwd
+ @object.description = src.description
+ @object.environment = src.environment
+ @object.mounts = src.mounts
+ @object.name = src.name
+ @object.output_path = src.output_path
+ @object.priority = 1
+ @object.properties[:template_uuid] = src.properties[:template_uuid]
+ @object.runtime_constraints = src.runtime_constraints
+ @object.scheduling_parameters = src.scheduling_parameters
+ @object.state = 'Uncommitted'
+ @object.use_existing = false
+
+ # set owner_uuid to that of source, provided it is a project and writable by current user
+ current_project = Group.find(src.owner_uuid) rescue nil
+ if (current_project && current_project.writable_by.andand.include?(current_user.uuid))
+ @object.owner_uuid = src.owner_uuid
+ end
+
+ super
+ end
end
end
@object.state = 'New'
- # set owner_uuid to that of source, provided it is a project and wriable by current user
+ # set owner_uuid to that of source, provided it is a project and writable by current user
current_project = Group.find(source.owner_uuid) rescue nil
if (current_project && current_project.writable_by.andand.include?(current_user.uuid))
@object.owner_uuid = source.owner_uuid
pane_list = []
procs = ["arvados#containerRequest"]
+ procs_pane_name = 'Processes'
if PipelineInstance.api_exists?(:index)
procs << "arvados#pipelineInstance"
+ procs_pane_name = 'Pipelines_and_processes'
end
workflows = ["arvados#workflow"]
}
pane_list <<
{
- :name => 'Pipelines_and_processes',
+ :name => procs_pane_name,
:filters => [%w(uuid is_a) + [procs]]
}
pane_list <<
link.destroy
end
- # If this object has the 'expires_at' attribute, then simply mark it
- # expired.
- if item.attributes.include?("expires_at")
- item.update_attributes expires_at: Time.now
+ # If this object has the 'trash_at' attribute, then simply mark it
+ # as trash.
+ if item.attributes.include?("trash_at")
+ item.update_attributes trash_at: Time.now
@removed_uuids << item.uuid
elsif item.owner_uuid == @object.uuid
# Object is owned by this project. Remove it from the project by
item.update_attributes owner_uuid: current_user.uuid
@removed_uuids << item.uuid
rescue ArvadosApiClient::ApiErrorResponseException => e
- if e.message.include? '_owner_uuid_name_unique'
+ if e.message.include? '_owner_uuid_'
rename_to = item.name + ' removed from ' +
(@object.name ? @object.name : @object.uuid) +
' at ' + Time.now.to_s
workflow = Workflow.find? template_uuid
if workflow.definition
begin
- wf_json = YAML::load(workflow.definition)
+ wf_json = ActiveSupport::HashWithIndifferentAccess.new YAML::load(workflow.definition)
rescue => e
logger.error "Error converting definition yaml to json: #{e.message}"
raise ArgumentError, "Error converting definition yaml to json: #{e.message}"
attrs['cwd'] = "/var/spool/cwl"
attrs['output_path'] = "/var/spool/cwl"
+ input_defaults = {}
+ if wf_json
+ inputs = get_cwl_inputs(wf_json)
+ inputs.each do |input|
+ if input[:default]
+ input_defaults[cwl_shortname(input[:id])] = input[:default]
+ end
+ end
+ end
+
# mounts
mounts = {
"/var/lib/cwl/cwl.input.json" => {
"kind" => "json",
- "content" => {}
+ "content" => input_defaults
},
"stdout" => {
"kind" => "file",
end
def log_collection
- get_combined(:log)
+ if @proxied.is_a?(ContainerRequest)
+ get(:log_uuid)
+ else
+ get(:log)
+ end
end
def outputs
items = []
- items << get_combined(:output) if get_combined(:output)
+ if @proxied.is_a?(ContainerRequest)
+ out = get(:output_uuid)
+ else
+ out = get(:output)
+ end
+ items << out if out
items
end
end
def cputime
- if state_label != "Queued"
+ if children.any?
+ children.map { |c|
+ c.cputime
+ }.reduce(:+) || 0
+ else
if started_at
- (runtime_constraints.andand[:min_nodes] || 1) * ((finished_at || Time.now()) - started_at)
+ (runtime_constraints.andand[:min_nodes] || 1).to_i * ((finished_at || Time.now()) - started_at)
+ else
+ 0
end
end
end
end
resp << " for "
- cpu_time = 0
- if children.any?
- cpu_time = children.map { |c|
- if c.started_at
- (c.runtime_constraints.andand[:min_nodes] || 1) * ((c.finished_at || Time.now()) - c.started_at)
- else
- 0
- end
- }.reduce(:+) || 0
- else
- if started_at
- cpu_time = (runtime_constraints.andand[:min_nodes] || 1) * ((finished_at || Time.now()) - started_at)
- end
- end
+ cpu_time = cputime
resp << ApplicationController.helpers.render_time(runningtime, false)
if (walltime - runningtime) > 0
<% if @object.class.goes_in_projects? && @object.uuid != current_user.andand.uuid # Not the "Home" project %>
<% content_for :tab_line_buttons do %>
+ <% if current_user.andand.is_active %>
+ <%= render partial: 'extra_tab_line_buttons' %>
+ <% end %>
<% if current_user.andand.is_active && @object.class.copies_to_projects? %>
<%= link_to(
choose_projects_path(
--- /dev/null
+<% if @object.state == 'Final' %>
+ <%= link_to(copy_container_request_path('id' => @object.uuid),
+ class: 'btn btn-primary',
+ title: 'Re-run',
+ data: {toggle: :tooltip, placement: :top}, title: 'This will make a copy and take you there. You can then make any needed changes and run it',
+ method: :post,
+ ) do %>
+ <i class="fa fa-fw fa-play"></i> Re-run
+ <% end %>
+<% end %>
-<% n_inputs = cwl_inputs_required(@object, get_cwl_inputs(@object.mounts[:"/var/lib/cwl/workflow.json"][:content]), [:mounts, :"/var/lib/cwl/cwl.input.json", :content]) %>
+<%
+n_inputs = if @object.mounts[:"/var/lib/cwl/workflow.json"] && @object.mounts[:"/var/lib/cwl/cwl.input.json"]
+ cwl_inputs_required(@object, get_cwl_inputs(@object.mounts[:"/var/lib/cwl/workflow.json"][:content]), [:mounts, :"/var/lib/cwl/cwl.input.json", :content])
+ else
+ 0
+ end
+%>
<% content_for :pi_input_form do %>
<form role="form" style="width:60%">
<div class="form-group">
- <% workflow = @object.mounts[:"/var/lib/cwl/workflow.json"][:content] %>
- <% inputs = get_cwl_inputs(workflow) %>
- <% inputs.each do |input| %>
- <label for="#input-<%= cwl_shortname(input[:id]) %>">
- <%= input[:label] || cwl_shortname(input[:id]) %>
- </label>
- <div>
- <p class="form-control-static">
- <%= render_cwl_input @object, input, [:mounts, :"/var/lib/cwl/cwl.input.json", :content] %>
+ <% workflow = @object.mounts[:"/var/lib/cwl/workflow.json"].andand[:content] %>
+ <% if workflow %>
+ <% inputs = get_cwl_inputs(workflow) %>
+ <% inputs.each do |input| %>
+ <label for="#input-<%= cwl_shortname(input[:id]) %>">
+ <%= input[:label] || cwl_shortname(input[:id]) %>
+ </label>
+ <div>
+ <p class="form-control-static">
+ <%= render_cwl_input @object, input, [:mounts, :"/var/lib/cwl/cwl.input.json", :content] %>
+ </p>
+ </div>
+ <p class="help-block">
+ <%= input[:doc] %>
</p>
- </div>
- <p class="help-block">
- <%= input[:doc] %>
- </p>
+ <% end %>
<% end %>
</div>
</form>
<div class="col-md-3">
<% if current_job[:started_at] %>
<% walltime = ((if current_job[:finished_at] then current_job[:finished_at] else Time.now() end) - current_job[:started_at]) %>
- <% cputime = (current_job[:runtime_constraints].andand[:min_nodes] || 1) *
+ <% cputime = (current_job[:runtime_constraints].andand[:min_nodes] || 1).to_i *
((current_job[:finished_at] || Time.now()) - current_job[:started_at]) %>
<%= render_runtime(walltime, false) %>
<% if cputime > 0 %> / <%= render_runtime(cputime, false) %> (<%= (cputime/walltime).round(1) %>⨯)<% end %>
<%
cputime = pipeline_jobs.map { |j|
if j[:job][:started_at]
- (j[:job][:runtime_constraints].andand[:min_nodes] || 1) * ((j[:job][:finished_at] || Time.now()) - j[:job][:started_at])
+ (j[:job][:runtime_constraints].andand[:min_nodes] || 1).to_i * ((j[:job][:finished_at] || Time.now()) - j[:job][:started_at])
else
0
end
preload_links_for_objects(collection_pdhs + collection_uuids)
%>
+<%
+ if !PipelineInstance.api_exists?(:index)
+ recent_procs_title = 'Recent processes'
+ run_proc_title = 'Choose a workflow to run:'
+ else
+ recent_procs_title = 'Recent pipelines and processes'
+ run_proc_title = 'Choose a pipeline or workflow to run:'
+ end
+%>
+
<div class="row">
<div class="col-md-6">
<div class="panel panel-default" style="min-height: 10.5em">
<div class="panel-heading">
- <span class="panel-title">Recent pipelines and processes</span>
+ <span class="panel-title"><%=recent_procs_title%></span>
<% if current_user.andand.is_active %>
<span class="pull-right recent-processes-actions">
<span>
<%= link_to(
choose_work_unit_templates_path(
- title: 'Choose a pipeline or workflow to run:',
+ title: run_proc_title,
action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
action_href: work_units_path,
action_method: 'post',
action_data: {'selection_param' => 'work_unit[template_uuid]', 'work_unit[owner_uuid]' => current_user.uuid, 'success' => 'redirect-to-created-object'}.to_json),
{ class: "btn btn-primary btn-xs", remote: true }) do %>
- <i class="fa fa-fw fa-gear"></i> Run a pipeline...
+ <i class="fa fa-fw fa-gear"></i> Run a process...
<% end %>
</span>
<span>
--- /dev/null
+<%= render_pane 'tab_contents', to_string: true, locals: {
+ limit: 50,
+ filters: [['uuid', 'is_a', ["arvados#containerRequest"]]],
+ sortable_columns: { 'name' => 'container_requests.name', 'description' => 'container_requests.description' }
+ }.merge(local_assigns) %>
</h2>
<% end %>
+<%
+ if !PipelineInstance.api_exists?(:index)
+ run_proc_title = 'Choose a workflow to run:'
+ run_proc_hover = 'Run a workflow in this project'
+ else
+ run_proc_title = 'Choose a pipeline or workflow to run:'
+ run_proc_hover = 'Run a pipeline or workflow in this project'
+ end
+%>
+
<% content_for :tab_line_buttons do %>
<% if @object.editable? %>
<div class="btn-group btn-group-sm">
</div>
<%= link_to(
choose_work_unit_templates_path(
- title: 'Choose a pipeline or workflow to run:',
+ title: run_proc_title,
action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
action_href: work_units_path,
action_method: 'post',
action_data: {'selection_param' => 'work_unit[template_uuid]', 'work_unit[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
- { class: "btn btn-primary btn-sm", remote: true, title: "Run a pipeline or workflow in this project" }) do %>
- <i class="fa fa-fw fa-gear"></i> Run a pipeline...
+ { class: "btn btn-primary btn-sm", remote: true, title: run_proc_hover }) do %>
+ <i class="fa fa-fw fa-gear"></i> Run a process...
<% end %>
<%= link_to projects_path({'project[owner_uuid]' => @object.uuid, 'options' => {'ensure_unique_name' => true}}), method: :post, title: "Add a subproject to this project", class: 'btn btn-sm btn-primary' do %>
<i class="fa fa-fw fa-plus"></i>
pipeline_2:
template_uuid: zzzzz-p5p6p-1xbobfobk94ppbv
input_paths: [zzzzz-4zz18-nz98douzhaa3jh2, zzzzz-4zz18-gpw9o5wpcti3nib]
+ container_requests_to_test:
+ container_request_1:
+ workflow_uuid: zzzzz-7fd4e-60e96shgwspt4mw
+ input_paths: []
+ max_wait_seconds: 10
# Below is a sample setting for performance testing.
# Configure workbench URL as "arvados_workbench_url"
resources :containers
resources :container_requests do
post 'cancel', :on => :member
+ post 'copy', on: :member
end
get '/virtual_machines/:id/webshell/:login' => 'virtual_machines#webshell', :as => :webshell_virtual_machine
resources :authorized_keys
--- /dev/null
+namespace :config do
+ desc 'Show site configuration'
+ task dump: :environment do
+ puts $application_config.to_yaml
+ end
+end
assert_includes @response.body, '<div id="event_log_div"'
assert_select 'Download the log', false
end
+
+ test "completed container request offers re-run option" do
+ use_token 'active'
+
+ uuid = api_fixture('container_requests')['completed']['uuid']
+
+ get :show, {id: uuid}, session_for(:active)
+ assert_response :success
+
+ assert_includes @response.body, "href=\"/container_requests/#{uuid}/copy\""
+ end
+
+ test "container request copy" do
+ completed_cr = api_fixture('container_requests')['completed']
+ post(:copy,
+ {
+ id: completed_cr['uuid']
+ },
+ session_for(:active))
+ assert_response 302
+ copied_cr = assigns(:object)
+ assert_not_nil copied_cr
+ assert_equal 'Uncommitted', copied_cr[:state]
+ assert_equal "Copy of #{completed_cr['name']}", copied_cr['name']
+ assert_equal completed_cr['cmd'], copied_cr['cmd']
+ assert_equal completed_cr['runtime_constraints']['ram'], copied_cr['runtime_constraints'][:ram]
+ end
end
get :index, {}, session_for(:active)
assert_includes @response.body, "zzzzz-xvhdp-cr4runningcntnr" # expect crs
assert_not_includes @response.body, "zzzzz-d1hrv-" # expect no pipelines
+ assert_includes @response.body, "Run a process"
end
[
end
[
+ :admin,
:active,
nil,
].each do |user|
assert_includes resp, "href=\"#Pipelines_and_processes\""
assert_includes resp, "href=\"#Workflows\""
assert_not_includes resp, "href=\"#Pipeline_templates\""
+ assert_includes @response.body, "Run a process" if user == :admin
end
end
end
end
test "project admin can remove collections from the project" do
- # Deleting an object that supports 'expires_at' should make it
- # completely inaccessible to API queries, not simply moved out of the project.
+ # Deleting an object that supports 'trash_at' should make it
+ # completely inaccessible to API queries, not simply moved out of
+ # the project.
coll_key = "collection_to_remove_from_subproject"
coll_uuid = api_fixture("collections")[coll_key]["uuid"]
delete(:remove_item,
use_token :subproject_admin
assert_raise ArvadosApiClient::NotFoundException do
- Collection.find(coll_uuid)
+ Collection.find(coll_uuid, cache: false)
end
end
test "project admin can remove items from project other than collections" do
- # An object which does not have an expired_at field (e.g. Specimen)
+ # An object which does not have an trash_at field (e.g. Specimen)
# should be implicitly moved to the user's Home project when removed.
specimen_uuid = api_fixture('specimens', 'in_asubproject')['uuid']
delete(:remove_item,
["user1_with_load", 2, ["project_with_10_collections"], "project_with_2_pipelines_and_60_crs"],
["admin", 5, ["anonymously_accessible_project", "subproject_in_anonymous_accessible_project"], "aproject"],
].each do |user, page_size, tree_segment, unexpected|
+ # Note: this test is sensitive to database collation. It passes
+ # with en_US.UTF-8.
test "build my projects tree for #{user} user and verify #{unexpected} is omitted" do
use_token user
- ctrl = ProjectsController.new
-
- current_user = User.find(api_fixture('users')[user]['uuid'])
- my_tree = ctrl.send :my_wanted_projects_tree, current_user, page_size
+ tree, _, _ = @controller.send(:my_wanted_projects_tree,
+ User.current,
+ page_size)
tree_segment_at_depth_1 = api_fixture('groups')[tree_segment[0]]
tree_segment_at_depth_2 = api_fixture('groups')[tree_segment[1]] if tree_segment[1]
- tree_nodes = {}
- my_tree[0].each do |x|
- tree_nodes[x[:object]['uuid']] = x[:depth]
+ node_depth = {}
+ tree.each do |x|
+ node_depth[x[:object]['uuid']] = x[:depth]
end
- assert_equal(1, tree_nodes[tree_segment_at_depth_1['uuid']])
- assert_equal(2, tree_nodes[tree_segment_at_depth_2['uuid']]) if tree_segment[1]
+ assert_equal(1, node_depth[tree_segment_at_depth_1['uuid']])
+ assert_equal(2, node_depth[tree_segment_at_depth_2['uuid']]) if tree_segment[1]
unexpected_project = api_fixture('groups')[unexpected]
- assert_nil(tree_nodes[unexpected_project['uuid']])
+ assert_nil(node_depth[unexpected_project['uuid']], node_depth.inspect)
end
end
--- /dev/null
+require 'diagnostics_test_helper'
+
+# This test assumes that the configured workflow_uuid corresponds to a cwl workflow.
+# Ex: configure a workflow using the steps below and use the resulting workflow uuid:
+# > cd arvados/doc/user/cwl/bwa-mem
+# > arvados-cwl-runner --create-workflow bwa-mem.cwl bwa-mem-input.yml
+
+class ContainerRequestTest < DiagnosticsTest
+ crs_to_test = Rails.configuration.container_requests_to_test.andand.keys
+
+ setup do
+ need_selenium 'to make websockets work'
+ end
+
+ crs_to_test.andand.each do |cr_to_test|
+ test "run container_request: #{cr_to_test}" do
+ cr_config = Rails.configuration.container_requests_to_test[cr_to_test]
+
+ visit_page_with_token 'active'
+
+ find('.btn', text: 'Run a process').click
+
+ within('.modal-dialog') do
+ page.find_field('Search').set cr_config['workflow_uuid']
+ wait_for_ajax
+ find('.selectable', text: 'bwa-mem.cwl').click
+ find('.btn', text: 'Next: choose inputs').click
+ end
+
+ page.assert_selector('a.disabled,button.disabled', text: 'Run') if cr_config['input_paths'].any?
+
+ # Choose input for the workflow
+ cr_config['input_paths'].each do |look_for|
+ select_input look_for
+ end
+ wait_for_ajax
+
+ # All needed input are already filled in. Run this workflow now
+ page.assert_no_selector('a.disabled,button.disabled', text: 'Run')
+ find('a,button', text: 'Run').click
+
+ # container_request is running. Run button is no longer available.
+ page.assert_no_selector('a', text: 'Run')
+
+ # Wait for container_request run to complete
+ wait_until_page_has 'completed', cr_config['max_wait_seconds']
+ end
+ end
+end
find('a,button', text: 'Components').click
find('a,button', text: 'Run').click
- # Pipeline is running. We have a "Stop" button instead now.
+ # Pipeline is running. We have a "Pause" button instead now.
page.assert_selector 'a,button', text: 'Pause'
# Wait for pipeline run to complete
wait_until_page_has 'completed', pipeline_config['max_wait_seconds']
end
end
-
- def select_input look_for
- inputs_needed = page.all('.btn', text: 'Choose')
- return if (!inputs_needed || !inputs_needed.any?)
-
- look_for_uuid = nil
- look_for_file = nil
- if look_for.andand.index('/').andand.>0
- partitions = look_for.partition('/')
- look_for_uuid = partitions[0]
- look_for_file = partitions[2]
- else
- look_for_uuid = look_for
- look_for_file = nil
- end
-
- assert_triggers_dom_event 'shown.bs.modal' do
- inputs_needed[0].click
- end
-
- within('.modal-dialog') do
- if look_for_uuid
- fill_in('Search', with: look_for_uuid, exact: true)
- wait_for_ajax
- end
-
- page.all('.selectable').first.click
- wait_for_ajax
- # ajax reload is wiping out input selection after search results; so, select again.
- page.all('.selectable').first.click
- wait_for_ajax
-
- if look_for_file
- wait_for_ajax
- within('.collection_files_name', text: look_for_file) do
- find('.fa-file').click
- end
- end
-
- find('button', text: 'OK').click
- wait_for_ajax
- end
- end
end
visit page_with_token(tokens[token_name], (workbench_url + path))
end
+ def select_input look_for
+ inputs_needed = page.all('.btn', text: 'Choose')
+ return if (!inputs_needed || !inputs_needed.any?)
+
+ look_for_uuid = nil
+ look_for_file = nil
+ if look_for.andand.index('/').andand.>0
+ partitions = look_for.partition('/')
+ look_for_uuid = partitions[0]
+ look_for_file = partitions[2]
+ else
+ look_for_uuid = look_for
+ look_for_file = nil
+ end
+
+ assert_triggers_dom_event 'shown.bs.modal' do
+ inputs_needed[0].click
+ end
+
+ within('.modal-dialog') do
+ if look_for_uuid
+ fill_in('Search', with: look_for_uuid, exact: true)
+ wait_for_ajax
+ end
+
+ page.all('.selectable').first.click
+ wait_for_ajax
+ # ajax reload is wiping out input selection after search results; so, select again.
+ page.all('.selectable').first.click
+ wait_for_ajax
+
+ if look_for_file
+ wait_for_ajax
+ within('.collection_files_name', text: look_for_file) do
+ find('.fa-file').click
+ end
+ end
+
+ find('button', text: 'OK').click
+ wait_for_ajax
+ end
+ end
+
# Looks for the text_to_look_for for up to the max_time provided
def wait_until_page_has text_to_look_for, max_time=30
max_time = 30 if (!max_time || (max_time.to_s != max_time.to_i.to_s))
assert_text 'Recent pipelines and processes' # seeing dashboard now
within('.recent-processes-actions') do
- assert page.has_link?('Run a pipeline')
+ assert page.has_link?('Run a process')
assert page.has_link?('All processes')
end
within('.recent-processes') do
- assert_text 'pipeline_with_job'
+ assert_text 'running'
within('.row-zzzzz-xvhdp-cr4runningcntnr') do
assert_text 'requester_for_running_cr'
assert_text 'completed container request'
within('.row-zzzzz-xvhdp-cr4completedctr')do
- assert page.has_link? '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'
+ assert page.has_link? 'foo_file'
end
end
wait_for_ajax
assert_text 'This container is queued'
end
+
+ test "Run button enabled when workflow is empty and no inputs are needed" do
+ visit page_with_token("active")
+
+ find('.btn', text: 'Run a process').click
+ within('.modal-dialog') do
+ find('.selectable', text: 'Valid workflow with no definition yaml').click
+ find('.btn', text: 'Next: choose inputs').click
+ end
+
+ assert_text 'This workflow does not need any further inputs'
+ page.assert_selector 'a', text: 'Run'
+ end
end
collection = api_fixture('collections', collection_fixture)
# create a pipeline instance
- find('.btn', text: 'Run a pipeline').click
+ find('.btn', text: 'Run a process').click
within('.modal-dialog') do
find('.selectable', text: template_name).click
find('.btn', text: 'Next: choose inputs').click
end
test "add new project using projects dropdown" do
- # verify that selection options are disabled on the project until an item is selected
visit page_with_token 'active', '/'
# Add a new project
click_link 'Add a new project'
assert_text 'New project'
assert_text 'No description provided'
-
- # Add one more new project
- find("#projects-menu").click
- click_link 'Add a new project'
- match = /New project \(\d\)/.match page.text
- assert match, 'Expected project name not found'
- assert_text 'No description provided'
end
test "first tab loads data when visiting other tab directly" do
project = api_fixture('groups')['aproject']
visit page_with_token 'active', '/projects/' + project['uuid']
- find('.btn', text: 'Run a pipeline').click
+ find('.btn', text: 'Run a process').click
# in the chooser, verify preview and click Next button
within('.modal-dialog') do
end
[
- ['Two Part Pipeline Template', 'part-one', 'Provide a value for the following'],
- ['Workflow with input specifications', 'this workflow has inputs specified', 'Provide a value for the following'],
+ ['Pipeline with default input specifications', 'part-one', 'Provide values for the following'],
+ ['Workflow with default input specifications', 'this workflow has inputs specified', 'Provide a value for the following'],
].each do |template_name, preview_txt, process_txt|
test "run a process using template #{template_name} from dashboard" do
visit page_with_token('admin')
within('.recent-processes-actions') do
assert page.has_link?('All processes')
- find('a', text: 'Run a pipeline').click
+ find('a', text: 'Run a process').click
end
# in the chooser, verify preview and click Next button
# in the process page now
assert_text process_txt
assert_selector 'a', text: template_name
+
+ assert_equal "Set value for ex_string_def", find('div.form-group > div > p.form-control-static > a', text: "hello-testing-123")[:"data-title"]
+
+ page.assert_selector 'a.disabled,button.disabled', text: 'Run'
end
end
test "home page" do
visit_page_with_token
assert_text 'Dashboard'
- assert_selector 'a', text: 'Run a pipeline'
+ assert_selector 'a', text: 'Run a process'
end
test "search for hash" do
end
[
- [Job, 'running_job_with_components', 1, 1, nil],
- [Job, 'queued', nil, nil, 1],
- [PipelineInstance, 'pipeline_in_running_state', 1, 1, nil],
- [PipelineInstance, 'has_component_with_completed_jobs', 60, 60, nil],
- ].each do |type, fixture, walltime, cputime, queuedtime|
+ [Job, 'running_job_with_components', 1, 1, nil, true],
+ [Job, 'queued', nil, 0, 1, false],
+ [PipelineInstance, 'pipeline_in_running_state', 1, 1, nil, false],
+ [PipelineInstance, 'has_component_with_completed_jobs', 60, 60, nil, true],
+ ].each do |type, fixture, walltime, cputime, queuedtime, cputime_more_than_walltime|
test "times for #{fixture}" do
use_token 'active'
obj = find_fixture(type, fixture)
else
assert_equal queuedtime, wu.queuedtime
end
+
+ assert_equal cputime_more_than_walltime, (wu.cputime > wu.walltime) if wu.cputime and wu.walltime
end
end
--- /dev/null
+case "$TARGET" in
+ ubuntu1204)
+ fpm_depends+=('libfuse2 = 2.9.2-5')
+ ;;
+esac
--- /dev/null
+case "$TARGET" in
+ ubuntu1204)
+ fpm_depends+=('libfuse2 = 2.9.2-5')
+ ;;
+esac
case "$TARGET" in
+ centos6)
+ build_depends+=('fuse-libs' 'fuse-devel')
+ fpm_depends+=(glibc 'fuse-libs = 2.9.2-5' 'fuse = 2.9.2-5')
+ ;;
centos*)
build_depends+=('fuse-devel')
fpm_depends+=(glibc fuse-libs)
;;
+ ubuntu1204)
+ build_depends+=(libfuse2 libfuse-dev)
+ fpm_depends+=(libc6 python-contextlib2 'libfuse2 = 2.9.2-5' 'fuse = 2.9.2-5')
+ ;;
debian* | ubuntu*)
build_depends+=('libfuse-dev')
- fpm_depends+=(libc6 libfuse2)
+ fpm_depends+=(libc6 'libfuse2 > 2.9.0' 'fuse > 2.9.0')
;;
esac
--- /dev/null
+case "$TARGET" in
+ centos6)
+ fpm_depends+=('fuse-libs = 2.9.2-5')
+ ;;
+esac
--- /dev/null
+case "$TARGET" in
+ centos6)
+ fpm_depends+=('fuse-libs = 2.9.2-5')
+ ;;
+esac
run-build-docker-images.sh Build arvbox Docker images.
-run-build-docker-jobs-image.sh Build arvados/jobs Docker image.
+run-build-docker-jobs-image.sh Build arvados/jobs Docker image
+ (uses published debian packages)
+
+build-dev-docker-jobs-image.sh Build developer arvados/jobs Docker image
+ (uses local git tree)
run-library.sh A library of functions shared by the
various scripts in this
--- /dev/null
+#!/bin/bash
+
+read -rd "\000" helpmessage <<EOF
+Build an arvados/jobs Docker image from local git tree.
+
+Intended for use by developers working on arvados-python-client or
+arvados-cwl-runner and need to run a crunch job with a custom package
+version. Also supports building custom cwltool if CWLTOOL is set.
+
+Syntax:
+ WORKSPACE=/path/to/arvados $(basename $0)
+
+WORKSPACE=path Path to the Arvados source tree to build packages from
+CWLTOOL=path (optional) Path to cwltool git repository.
+
+EOF
+
+set -e
+
+if [[ -z "$WORKSPACE" ]] ; then
+ echo "$helpmessage"
+ echo
+ echo "Must set WORKSPACE"
+ exit 1
+fi
+
+if [[ -z "$ARVADOS_API_HOST" || -z "$ARVADOS_API_TOKEN" ]] ; then
+ echo "$helpmessage"
+ echo
+ echo "Must set ARVADOS_API_HOST and ARVADOS_API_TOKEN"
+ exit 1
+fi
+
+cd "$WORKSPACE"
+
+(cd sdk/python && python setup.py sdist)
+sdk=$(cd sdk/python/dist && ls -t arvados-python-client-*.tar.gz | head -n1)
+
+(cd sdk/cwl && python setup.py sdist)
+runner=$(cd sdk/cwl/dist && ls -t arvados-cwl-runner-*.tar.gz | head -n1)
+
+rm -rf sdk/cwl/cwltool_dist
+mkdir -p sdk/cwl/cwltool_dist
+if [[ -n "$CWLTOOL" ]] ; then
+ (cd "$CWLTOOL" && python setup.py sdist)
+ cwltool=$(cd "$CWLTOOL/dist" && ls -t cwltool-*.tar.gz | head -n1)
+ cp "$CWLTOOL/dist/$cwltool" $WORKSPACE/sdk/cwl/cwltool_dist
+fi
+
+. build/run-library.sh
+
+python_sdk_ts=$(cd sdk/python && timestamp_from_git)
+cwl_runner_ts=$(cd sdk/cwl && timestamp_from_git)
+
+if [[ $python_sdk_ts -gt $cwl_runner_ts ]]; then
+ gittag=$(git log --first-parent --max-count=1 --format=format:%H sdk/python)
+else
+ gittag=$(git log --first-parent --max-count=1 --format=format:%H sdk/cwl)
+fi
+
+docker build --build-arg sdk=$sdk --build-arg runner=$runner --build-arg cwltool=$cwltool -f "$WORKSPACE/sdk/dev-jobs.dockerfile" -t arvados/jobs:$gittag "$WORKSPACE/sdk"
+echo arv-keepdocker arvados/jobs $gittag
+arv-keepdocker arvados/jobs $gittag
-LIBCLOUD_PIN=0.20.2.dev1
\ No newline at end of file
+LIBCLOUD_PIN=0.20.2.dev2
\ No newline at end of file
-all: centos6/generated centos7/generated debian7/generated debian8/generated ubuntu1204/generated ubuntu1404/generated
-
-centos6/generated: common-generated-all
- test -d centos6/generated || mkdir centos6/generated
- cp -rlt centos6/generated common-generated/*
+all: centos7/generated debian8/generated ubuntu1204/generated ubuntu1404/generated
centos7/generated: common-generated-all
test -d centos7/generated || mkdir centos7/generated
cp -rlt centos7/generated common-generated/*
-debian7/generated: common-generated-all
- test -d debian7/generated || mkdir debian7/generated
- cp -rlt debian7/generated common-generated/*
-
debian8/generated: common-generated-all
test -d debian8/generated || mkdir debian8/generated
cp -rlt debian8/generated common-generated/*
+++ /dev/null
-FROM centos:6
-MAINTAINER Brett Smith <brett@curoverse.com>
-
-# Install build dependencies provided in base distribution
-RUN yum -q -y install make automake gcc gcc-c++ libyaml-devel patch readline-devel zlib-devel libffi-devel openssl-devel bzip2 libtool bison sqlite-devel rpm-build git perl-ExtUtils-MakeMaker libattr-devel nss-devel libcurl-devel which tar unzip scl-utils centos-release-scl postgresql-devel
-
-# Install golang binary
-ADD generated/go1.7.1.linux-amd64.tar.gz /usr/local/
-RUN ln -s /usr/local/go/bin/go /usr/local/bin/
-
-# Install RVM
-RUN gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
- curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1 && \
- /usr/local/rvm/bin/rvm-exec default gem install bundler && \
- /usr/local/rvm/bin/rvm-exec default gem install cure-fpm --version 1.6.0b
-
-# Need to "touch" RPM database to workaround bug in interaction between
-# overlayfs and yum (https://bugzilla.redhat.com/show_bug.cgi?id=1213602)
-RUN touch /var/lib/rpm/* && yum -q -y install python27 python33
-RUN scl enable python33 "easy_install-3.3 pip" && scl enable python27 "easy_install-2.7 pip"
-
-# fpm requires ffi which now wants xz-libs-5 which isn't packaged for centos6
-# but the library from xz-libs-4.999 appears to be good enough.
-RUN ln -s /usr/lib64/liblzma.so.0 /usr/lib64/lzma.so.5
-
-RUN cd /tmp && \
- (curl -OLf 'http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm' || \
- curl -OLf 'http://repoforge.eecs.wsu.edu/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm') && \
- rpm -ivh rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm && \
- sed -i 's/enabled = 0/enabled = 1/' /etc/yum.repos.d/rpmforge.repo
-
-RUN touch /var/lib/rpm/* && yum install --assumeyes git
-
-ENV WORKSPACE /arvados
-CMD ["scl", "enable", "python33", "python27", "/usr/local/rvm/bin/rvm-exec default bash /jenkins/run-build-packages.sh --target centos6"]
+++ /dev/null
-FROM debian:wheezy
-MAINTAINER Ward Vandewege <ward@curoverse.com>
-
-# Install dependencies and set up system.
-RUN /usr/bin/apt-get update && /usr/bin/apt-get install -q -y python2.7-dev python3 python-setuptools python3-setuptools libcurl4-gnutls-dev curl git procps libattr1-dev libfuse-dev libpq-dev python-pip unzip
-
-# Install RVM
-RUN gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
- curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1 && \
- /usr/local/rvm/bin/rvm-exec default gem install bundler && \
- /usr/local/rvm/bin/rvm-exec default gem install cure-fpm --version 1.6.0b
-
-# Install golang binary
-ADD generated/go1.7.1.linux-amd64.tar.gz /usr/local/
-RUN ln -s /usr/local/go/bin/go /usr/local/bin/
-
-ENV WORKSPACE /arvados
-CMD ["/usr/local/rvm/bin/rvm-exec", "default", "bash", "/jenkins/run-build-packages.sh", "--target", "debian7"]
+++ /dev/null
-FROM centos:6
-MAINTAINER Peter Amstutz <peter.amstutz@curoverse.com>
-
-RUN yum -q install --assumeyes scl-utils centos-release-scl \
- which tar
-
-# Install RVM
-RUN touch /var/lib/rpm/* && \
- gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
- curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1 && \
- /usr/local/rvm/bin/rvm-exec default gem install bundle && \
- /usr/local/rvm/bin/rvm-exec default gem install cure-fpm --version 1.6.0b
-
-RUN cd /tmp && \
- (curl -OLf 'http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm' || \
- curl -OLf 'http://repoforge.eecs.wsu.edu/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm') && \
- rpm -ivh rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm && \
- sed -i 's/enabled = 0/enabled = 1/' /etc/yum.repos.d/rpmforge.repo
-
-COPY localrepo.repo /etc/yum.repos.d/localrepo.repo
+++ /dev/null
-[localrepo]
-name=Arvados Test
-baseurl=file:///arvados/packages/centos6
-gpgcheck=0
-enabled=1
RUN touch /var/lib/rpm/* && \
gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1 && \
+ /usr/local/rvm/bin/rvm install 2.3 && \
+ /usr/local/rvm/bin/rvm alias create default ruby-2.3 && \
/usr/local/rvm/bin/rvm-exec default gem install bundle && \
/usr/local/rvm/bin/rvm-exec default gem install cure-fpm --version 1.6.0b
+++ /dev/null
-FROM debian:7
-MAINTAINER Peter Amstutz <peter.amstutz@curoverse.com>
-
-# Install RVM
-RUN apt-get update && apt-get -y install curl procps && \
- gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
- curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1
-
-# udev daemon can't start in a container, so don't try.
-RUN mkdir -p /etc/udev/disabled
-
-RUN echo "deb file:///arvados/packages/debian7/ /" >>/etc/apt/sources.list
MAINTAINER Peter Amstutz <peter.amstutz@curoverse.com>
# Install RVM
-RUN apt-get update && apt-get -y install curl && \
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends curl ca-certificates && \
gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1
+ /usr/local/rvm/bin/rvm install 2.3 && \
+ /usr/local/rvm/bin/rvm alias create default ruby-2.3
# udev daemon can't start in a container, so don't try.
RUN mkdir -p /etc/udev/disabled
MAINTAINER Peter Amstutz <peter.amstutz@curoverse.com>
# Install RVM
-RUN apt-get update && apt-get -y install curl && \
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends curl ca-certificates && \
gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1
+ /usr/local/rvm/bin/rvm install 2.3 && \
+ /usr/local/rvm/bin/rvm alias create default ruby-2.3
# udev daemon can't start in a container, so don't try.
RUN mkdir -p /etc/udev/disabled
-RUN echo "deb file:///arvados/packages/ubuntu1204/ /" >>/etc/apt/sources.list
\ No newline at end of file
+RUN echo "deb file:///arvados/packages/ubuntu1204/ /" >>/etc/apt/sources.list
MAINTAINER Peter Amstutz <peter.amstutz@curoverse.com>
# Install RVM
-RUN apt-get update && apt-get -y install curl && \
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends curl ca-certificates && \
gpg --keyserver pool.sks-keyservers.net --recv-keys D39DC0E3 && \
curl -L https://get.rvm.io | bash -s stable && \
- /usr/local/rvm/bin/rvm install 2.1 && \
- /usr/local/rvm/bin/rvm alias create default ruby-2.1
+ /usr/local/rvm/bin/rvm install 2.3 && \
+ /usr/local/rvm/bin/rvm alias create default ruby-2.3
# udev daemon can't start in a container, so don't try.
RUN mkdir -p /etc/udev/disabled
-RUN echo "deb file:///arvados/packages/ubuntu1404/ /" >>/etc/apt/sources.list
\ No newline at end of file
+RUN echo "deb file:///arvados/packages/ubuntu1404/ /" >>/etc/apt/sources.list
+++ /dev/null
-rpm-common-test-packages.sh
\ No newline at end of file
prepare_database() {
DB_MIGRATE_STATUS=`$COMMAND_PREFIX bundle exec rake db:migrate:status 2>&1 || true`
- if echo $DB_MIGRATE_STATUS | grep -qF 'Schema migrations table does not exist yet.'; then
+ if echo "$DB_MIGRATE_STATUS" | grep -qF 'Schema migrations table does not exist yet.'; then
# The database exists, but the migrations table doesn't.
run_and_report "Setting up database" $COMMAND_PREFIX bundle exec \
rake "$RAILSPKG_DATABASE_LOAD_TASK" db:seed
- elif echo $DB_MIGRATE_STATUS | grep -q '^database: '; then
+ elif echo "$DB_MIGRATE_STATUS" | grep -q '^database: '; then
run_and_report "Running db:migrate" \
$COMMAND_PREFIX bundle exec rake db:migrate
- elif echo $DB_MIGRATE_STATUS | grep -q 'database .* does not exist'; then
+ elif echo "$DB_MIGRATE_STATUS" | grep -q 'database .* does not exist'; then
if ! run_and_report "Running db:setup" \
$COMMAND_PREFIX bundle exec rake db:setup 2>/dev/null; then
echo "Warning: unable to set up database." >&2
timer_reset
-if [[ "$ECODE" != "0" ]]; then
+if [[ "$EXITCODE" != "0" ]]; then
title "upload arvados images SKIPPED because build failed"
else
if [[ $upload == true ]]; then
FINAL_EXITCODE=0
-for dockerfile_path in $(find -name Dockerfile); do
+for dockerfile_path in $(find -name Dockerfile | grep package-build-dockerfiles); do
if ./run-build-packages-one-target.sh --target "$(basename $(dirname "$dockerfile_path"))" --command "$COMMAND" $DEBUG $TEST_PACKAGES $ONLY_TEST ; then
true
else
WORKSPACE=/path/to/arvados $(basename $0) [options]
--target <target>
- Distribution to build packages for (default: debian7)
+ Distribution to build packages for (default: debian8)
--command
Build command to execute (default: use built-in Docker image command)
--test-packages
Run package install test script "test-packages-$target.sh"
--debug
Output debug information (default: false)
---only-test
+--only-build <package>
+ Build only a specific package
+--only-test <package>
Test only a specific package
WORKSPACE=path Path to the Arvados source tree to build packages from
fi
PARSEDOPTS=$(getopt --name "$0" --longoptions \
- help,debug,test-packages,target:,command:,only-test: \
+ help,debug,test-packages,target:,command:,only-test:,only-build: \
-- "" "$@")
if [ $? -ne 0 ]; then
exit 1
fi
-TARGET=debian7
+TARGET=debian8
COMMAND=
DEBUG=
TARGET="$2"; shift
;;
--only-test)
+ test_packages=1
packages="$2"; shift
;;
+ --only-build)
+ ONLY_BUILD="$2"; shift
+ ;;
--debug)
DEBUG=" --debug"
;;
if test -z "$packages" ; then
packages="arvados-api-server
- arvados-data-manager
arvados-docker-cleaner
arvados-git-httpd
arvados-node-manager
libarvados-perl"
case "$TARGET" in
- centos6)
- packages="$packages python27-python-arvados-fuse
- python27-python-arvados-python-client python27-python-arvados-cwl-runner"
- ;;
*)
packages="$packages python-arvados-fuse
python-arvados-python-client python-arvados-cwl-runner"
if [[ -n "$test_packages" ]]; then
for p in $packages ; do
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$p" != "$ONLY_BUILD" ]]; then
+ continue
+ fi
echo
echo "START: $p test on $IMAGE" >&2
if docker run --rm \
if docker run --rm \
"${docker_volume_args[@]}" \
--env ARVADOS_DEBUG=1 \
+ --env "ONLY_BUILD=$ONLY_BUILD" \
"$IMAGE" $COMMAND
then
echo
--debug
Output debug information (default: false)
--target
- Distribution to build packages for (default: debian7)
+ Distribution to build packages for (default: debian8)
WORKSPACE=path Path to the Arvados SSO source tree to build packages from
EXITCODE=0
DEBUG=${ARVADOS_DEBUG:-0}
-TARGET=debian7
+TARGET=debian8
PARSEDOPTS=$(getopt --name "$0" --longoptions \
help,build-bundle-packages,debug,target: \
fi
case "$TARGET" in
- debian7)
- FORMAT=deb
- ;;
debian8)
FORMAT=deb
;;
ubuntu1404)
FORMAT=deb
;;
- centos6|centos7)
+ centos7)
FORMAT=rpm
;;
*)
Build api server and workbench packages with vendor/bundle included
--debug
Output debug information (default: false)
---target
- Distribution to build packages for (default: debian7)
+--target <target>
+ Distribution to build packages for (default: debian8)
+--only-build <package>
+ Build only a specific package (or $ONLY_BUILD from environment)
--command
Build command to execute (defaults to the run command defined in the
Docker image)
EXITCODE=0
DEBUG=${ARVADOS_DEBUG:-0}
-TARGET=debian7
+TARGET=debian8
COMMAND=
PARSEDOPTS=$(getopt --name "$0" --longoptions \
- help,build-bundle-packages,debug,target: \
+ help,build-bundle-packages,debug,target:,only-build: \
-- "" "$@")
if [ $? -ne 0 ]; then
exit 1
--target)
TARGET="$2"; shift
;;
+ --only-build)
+ ONLY_BUILD="$2"; shift
+ ;;
--debug)
DEBUG=1
;;
## End Debian Python defaults.
case "$TARGET" in
- debian7)
- FORMAT=deb
- PYTHON_BACKPORTS=(python-gflags==2.0 google-api-python-client==1.4.2 \
- oauth2client==1.5.2 pyasn1==0.1.7 pyasn1-modules==0.0.5 \
- rsa uritemplate httplib2 ws4py pykka six \
- ciso8601 pycrypto backports.ssl_match_hostname llfuse==0.41.1 \
- 'pycurl<7.21.5' contextlib2 pyyaml 'rdflib>=4.2.0' \
- shellescape mistune typing avro ruamel.ordereddict
- cachecontrol requests)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client)
- ;;
debian8)
FORMAT=deb
PYTHON_BACKPORTS=(python-gflags==2.0 google-api-python-client==1.4.2 \
oauth2client==1.5.2 pyasn1==0.1.7 pyasn1-modules==0.0.5 \
- rsa uritemplate httplib2 ws4py pykka six \
+ rsa uritemplate httplib2 ws4py pykka six \
ciso8601 pycrypto backports.ssl_match_hostname llfuse==0.41.1 \
'pycurl<7.21.5' pyyaml 'rdflib>=4.2.0' \
shellescape mistune typing avro ruamel.ordereddict
- cachecontrol)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client)
+ cachecontrol junit-xml==1.7 futures==3.0.5)
+ PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client==0.37.0)
;;
ubuntu1204)
FORMAT=deb
PYTHON_BACKPORTS=(python-gflags==2.0 google-api-python-client==1.4.2 \
oauth2client==1.5.2 pyasn1==0.1.7 pyasn1-modules==0.0.5 \
- rsa uritemplate httplib2 ws4py pykka six \
+ rsa uritemplate httplib2 ws4py pykka six \
ciso8601 pycrypto backports.ssl_match_hostname llfuse==0.41.1 \
contextlib2 'pycurl<7.21.5' pyyaml 'rdflib>=4.2.0' \
shellescape mistune typing avro isodate ruamel.ordereddict
- cachecontrol requests)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client)
+ cachecontrol requests junit-xml==1.7 futures==3.0.5)
+ PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client==0.37.0)
;;
ubuntu1404)
FORMAT=deb
google-api-python-client==1.4.2 six uritemplate oauth2client==1.5.2 httplib2 \
rsa 'pycurl<7.21.5' backports.ssl_match_hostname pyyaml 'rdflib>=4.2.0' \
shellescape mistune typing avro ruamel.ordereddict
- cachecontrol)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 requests websocket-client)
- ;;
- centos6)
- FORMAT=rpm
- PYTHON2_PACKAGE=$(rpm -qf "$(which python$PYTHON2_VERSION)" --queryformat '%{NAME}\n')
- PYTHON2_PKG_PREFIX=$PYTHON2_PACKAGE
- PYTHON2_PREFIX=/opt/rh/python27/root/usr
- PYTHON2_INSTALL_LIB=lib/python$PYTHON2_VERSION/site-packages
- PYTHON3_PACKAGE=$(rpm -qf "$(which python$PYTHON3_VERSION)" --queryformat '%{NAME}\n')
- PYTHON3_PKG_PREFIX=$PYTHON3_PACKAGE
- PYTHON3_PREFIX=/opt/rh/python33/root/usr
- PYTHON3_INSTALL_LIB=lib/python$PYTHON3_VERSION/site-packages
- PYTHON_BACKPORTS=(python-gflags==2.0 google-api-python-client==1.4.2 \
- oauth2client==1.5.2 pyasn1==0.1.7 pyasn1-modules==0.0.5 \
- rsa uritemplate httplib2 ws4py pykka six \
- ciso8601 pycrypto backports.ssl_match_hostname 'pycurl<7.21.5' \
- python-daemon llfuse==0.41.1 'pbr<1.0' pyyaml \
- 'rdflib>=4.2.0' shellescape mistune typing avro requests \
- isodate pyparsing sparqlwrapper html5lib==0.9999999 keepalive \
- ruamel.ordereddict cachecontrol)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client)
- export PYCURL_SSL_LIBRARY=nss
+ cachecontrol junit-xml==1.7 futures==3.0.5)
+ PYTHON3_BACKPORTS=(docker-py==1.7.2 requests websocket-client==0.37.0)
;;
centos7)
FORMAT=rpm
oauth2client==1.5.2 pyasn1==0.1.7 pyasn1-modules==0.0.5 \
rsa uritemplate httplib2 ws4py pykka \
ciso8601 pycrypto 'pycurl<7.21.5' \
- python-daemon==2.1.1 llfuse==0.41.1 'pbr<1.0' pyyaml \
+ python-daemon==2.1.1 llfuse==0.41.1 'pbr<1.0' pyyaml contextlib2 \
'rdflib>=4.2.0' shellescape mistune typing avro \
isodate pyparsing sparqlwrapper html5lib==0.9999999 keepalive \
- ruamel.ordereddict cachecontrol)
- PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client)
+ ruamel.ordereddict cachecontrol junit-xml==1.7 futures==3.0.5)
+ PYTHON3_BACKPORTS=(docker-py==1.7.2 six requests websocket-client==0.37.0)
export PYCURL_SSL_LIBRARY=nss
;;
*)
# Perl packages
debug_echo -e "\nPerl packages\n"
+if [[ -z "$ONLY_BUILD" ]] || [[ "libarvados-perl" = "$ONLY_BUILD" ]] ; then
cd "$WORKSPACE/sdk/perl"
if [[ -e Makefile ]]; then
"Curoverse, Inc." dir "$(version_from_git)" install/man/=/usr/share/man \
"$WORKSPACE/LICENSE-2.0.txt=/usr/share/doc/libarvados-perl/LICENSE-2.0.txt" && \
mv --no-clobber libarvados-perl*.$FORMAT "$WORKSPACE/packages/$TARGET/"
+fi
# Ruby gems
debug_echo -e "\nRuby gems\n"
"$WORKSPACE/packages/$TARGET/libfuse-dev_2.9.2-5_amd64.deb"
apt-get -y --no-install-recommends -f install
rm -rf $LIBFUSE_DIR
-elif [[ $TARGET =~ centos6 ]]; then
- # port fuse 2.9.2 to centos 6
- # install tools to build rpm from source
- yum install -y rpm-build redhat-rpm-config
- LIBFUSE_DIR=$(mktemp -d)
- (
- cd "$LIBFUSE_DIR"
- # download fuse 2.9.2 centos 7 source rpm
- file="fuse-2.9.2-6.el7.src.rpm" && curl -L -o "${file}" "http://vault.centos.org/7.2.1511/os/Source/SPackages/${file}"
- (
- # modify source rpm spec to remove conflict on filesystem version
- mkdir -p /root/rpmbuild/SOURCES
- cd /root/rpmbuild/SOURCES
- rpm2cpio ${LIBFUSE_DIR}/fuse-2.9.2-6.el7.src.rpm | cpio -i
- perl -pi -e 's/Conflicts:\s*filesystem.*//g' fuse.spec
- )
- # build rpms from source
- rpmbuild -bb /root/rpmbuild/SOURCES/fuse.spec
- rm -f fuse-2.9.2-6.el7.src.rpm
- # move built RPMs to LIBFUSE_DIR
- mv "/root/rpmbuild/RPMS/x86_64/fuse-2.9.2-6.el6.x86_64.rpm" ${LIBFUSE_DIR}/
- mv "/root/rpmbuild/RPMS/x86_64/fuse-libs-2.9.2-6.el6.x86_64.rpm" ${LIBFUSE_DIR}/
- mv "/root/rpmbuild/RPMS/x86_64/fuse-devel-2.9.2-6.el6.x86_64.rpm" ${LIBFUSE_DIR}/
- rm -rf /root/rpmbuild
- )
- fpm_build "$LIBFUSE_DIR/fuse-libs-2.9.2-6.el6.x86_64.rpm" fuse-libs "Centos Developers" rpm "2.9.2" --iteration 5
- fpm_build "$LIBFUSE_DIR/fuse-2.9.2-6.el6.x86_64.rpm" fuse "Centos Developers" rpm "2.9.2" --iteration 5 --no-auto-depends
- fpm_build "$LIBFUSE_DIR/fuse-devel-2.9.2-6.el6.x86_64.rpm" fuse-devel "Centos Developers" rpm "2.9.2" --iteration 5 --no-auto-depends
- yum install -y \
- "$WORKSPACE/packages/$TARGET/fuse-libs-2.9.2-5.x86_64.rpm" \
- "$WORKSPACE/packages/$TARGET/fuse-2.9.2-5.x86_64.rpm" \
- "$WORKSPACE/packages/$TARGET/fuse-devel-2.9.2-5.x86_64.rpm"
fi
# Go binaries
"Supervise a single Crunch container"
package_go_binary services/crunchstat crunchstat \
"Gather cpu/memory/network statistics of running Crunch jobs"
-package_go_binary services/datamanager arvados-data-manager \
- "Ensure block replication levels, report disk usage, and determine which blocks should be deleted when space is needed"
package_go_binary services/keep-balance keep-balance \
"Rebalance and garbage-collect data blocks stored in Arvados Keep"
package_go_binary services/keepproxy keepproxy \
"Keep storage daemon, accessible to clients on the LAN"
package_go_binary services/keep-web keep-web \
"Static web hosting service for user data stored in Arvados Keep"
+package_go_binary services/ws arvados-ws \
+ "Arvados Websocket server"
package_go_binary tools/keep-block-check keep-block-check \
"Verify that all data from one set of Keep servers to another was copied"
package_go_binary tools/keep-rsync keep-rsync \
# 2014-05-15
cd $WORKSPACE/packages/$TARGET
rm -rf "$WORKSPACE/sdk/python/build"
-fpm_build $WORKSPACE/sdk/python "${PYTHON2_PKG_PREFIX}-arvados-python-client" 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/sdk/python/arvados_python_client.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados Python SDK" --deb-recommends=git
+fpm_build $WORKSPACE/sdk/python "${PYTHON2_PKG_PREFIX}-arvados-python-client" 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/sdk/python/arvados_python_client.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados Python SDK" --depends "${PYTHON2_PKG_PREFIX}-setuptools" --deb-recommends=git
# cwl-runner
cd $WORKSPACE/packages/$TARGET
# So we build this thing separately.
#
# Ward, 2016-03-17
-fpm_build schema_salad "" "" python 1.18.20161005190847 --depends "${PYTHON2_PKG_PREFIX}-lockfile >= 1:0.12.2-2"
+saladversion=$(cat "$WORKSPACE/sdk/cwl/setup.py" | grep schema-salad== | sed "s/.*==\(.*\)'.*/\1/")
+fpm_build schema_salad "" "" python $saladversion --depends "${PYTHON2_PKG_PREFIX}-lockfile >= 1:0.12.2-2"
# And schema_salad now depends on ruamel-yaml, which apparently has a braindead setup.py that requires special arguments to build (otherwise, it aborts with 'error: you have to install with "pip install ."'). Sigh.
# Ward, 2016-05-26
-fpm_build ruamel.yaml "" "" python 0.12.4 --python-setup-py-arguments "--single-version-externally-managed"
+fpm_build ruamel.yaml "" "" python 0.13.7 --python-setup-py-arguments "--single-version-externally-managed"
# Dependency of cwltool. Fpm doesn't produce a package with the correct version
# number unless we build it explicitly
-fpm_build cwltest "" "" python 1.0.20160907111242
+fpm_build cwltest "" "" python 1.0.20161227194859 --depends "${PYTHON2_PKG_PREFIX}-futures >= 3.0.5" --iteration 3
# And for cwltool we have the same problem as for schema_salad. Ward, 2016-03-17
-fpm_build cwltool "" "" python 1.0.20161107145355
+cwltoolversion=$(cat "$WORKSPACE/sdk/cwl/setup.py" | grep cwltool== | sed "s/.*==\(.*\)'.*/\1/")
+fpm_build cwltool "" "" python $cwltoolversion
# FPM eats the trailing .0 in the python-rdflib-jsonld package when built with 'rdflib-jsonld>=0.3.0'. Force the version. Ward, 2016-03-25
-fpm_build rdflib-jsonld "" "" python 0.3.0
+fpm_build rdflib-jsonld "" "" python 0.4.0
# The PAM module
if [[ $TARGET =~ debian|ubuntu ]]; then
# not omit the python- prefix first.
cd $WORKSPACE/packages/$TARGET
rm -rf "$WORKSPACE/services/fuse/build"
-fpm_build $WORKSPACE/services/fuse "${PYTHON2_PKG_PREFIX}-arvados-fuse" 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/fuse/arvados_fuse.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Keep FUSE driver"
+fpm_build $WORKSPACE/services/fuse "${PYTHON2_PKG_PREFIX}-arvados-fuse" 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/fuse/arvados_fuse.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Keep FUSE driver" --depends "${PYTHON2_PKG_PREFIX}-setuptools"
# The node manager
cd $WORKSPACE/packages/$TARGET
rm -rf "$WORKSPACE/services/nodemanager/build"
-fpm_build $WORKSPACE/services/nodemanager arvados-node-manager 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/nodemanager/arvados_node_manager.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados node manager"
+fpm_build $WORKSPACE/services/nodemanager arvados-node-manager 'Curoverse, Inc.' 'python' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/nodemanager/arvados_node_manager.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados node manager" --depends "${PYTHON2_PKG_PREFIX}-setuptools"
# The Docker image cleaner
cd $WORKSPACE/packages/$TARGET
rm -rf "$WORKSPACE/services/dockercleaner/build"
-fpm_build $WORKSPACE/services/dockercleaner arvados-docker-cleaner 'Curoverse, Inc.' 'python3' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/dockercleaner/arvados_docker_cleaner.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados Docker image cleaner"
+fpm_build $WORKSPACE/services/dockercleaner arvados-docker-cleaner 'Curoverse, Inc.' 'python3' "$(awk '($1 == "Version:"){print $2}' $WORKSPACE/services/dockercleaner/arvados_docker_cleaner.egg-info/PKG-INFO)" "--url=https://arvados.org" "--description=The Arvados Docker image cleaner" --depends "${PYTHON3_PKG_PREFIX}-websocket-client = 0.37.0" --iteration 3
# The Arvados crunchstat-summary tool
cd $WORKSPACE/packages/$TARGET
for deppkg in "${PYTHON_BACKPORTS[@]}"; do
outname=$(echo "$deppkg" | sed -e 's/^python-//' -e 's/[<=>].*//' -e 's/_/-/g' -e "s/^/${PYTHON2_PKG_PREFIX}-/")
+
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$outname" != "$ONLY_BUILD" ]] ; then
+ continue
+ fi
+
case "$deppkg" in
httplib2|google-api-python-client)
# Work around 0640 permissions on some package files.
--license="GNU Affero General Public License, version 3.0"
# Build the workbench server package
+if [[ -z "$ONLY_BUILD" ]] || [[ "arvados-workbench" = "$ONLY_BUILD" ]] ; then
(
set -e
cd "$WORKSPACE/apps/workbench"
# Remove generated configuration files so they don't go in the package.
rm config/application.yml config/environments/production.rb
)
+fi
if [[ "$?" != "0" ]]; then
echo "ERROR: Asset precompilation failed"
WORKSPACE=/path/to/arvados $(basename $0) [options]
--target <target>
- Distribution to build packages for (default: debian7)
+ Distribution to build packages for (default: debian8)
--upload
If the build and test steps are successful, upload the packages
to a remote apt repository (default: false)
exit 1
fi
-TARGET=debian7
+TARGET=debian8
UPLOAD=0
eval set -- "$PARSEDOPTS"
local gem_version="$(nohash_version_from_git)"
local gem_src_dir="$(pwd)"
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$gem_name" != "$ONLY_BUILD" ]] ; then
+ return 0
+ fi
+
if ! [[ -e "${gem_name}-${gem_version}.gem" ]]; then
find -maxdepth 1 -name "${gem_name}-*.gem" -delete
local description="$1"; shift
local license_file="${1:-agpl-3.0.txt}"; shift
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$prog" != "$ONLY_BUILD" ]] ; then
+ return 0
+ fi
+
debug_echo "package_go_binary $src_path as $prog"
local basename="${src_path##*/}"
handle_rails_package() {
local pkgname="$1"; shift
+
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$pkgname" != "$ONLY_BUILD" ]] ; then
+ return 0
+ fi
+
local srcdir="$1"; shift
local license_path="$1"; shift
local scripts_dir="$(mktemp --tmpdir -d "$pkgname-XXXXXXXX.scripts")" && \
local -a pos_args=("$srcdir/=$railsdir" "$pkgname" "Curoverse, Inc." dir
"$(cat "$version_file")")
local license_arg="$license_path=$railsdir/$(basename "$license_path")"
- local -a switches=(--iteration=6
+ local -a switches=(--iteration=7
--after-install "$scripts_dir/postinst"
--before-remove "$scripts_dir/prerm"
--after-remove "$scripts_dir/postrm")
VERSION=$1
shift
+ if [[ -n "$ONLY_BUILD" ]] && [[ "$PACKAGE_NAME" != "$ONLY_BUILD" ]] && [[ "$PACKAGE" != "$ONLY_BUILD" ]] ; then
+ return 0
+ fi
+
local default_iteration_value="$(default_iteration "$PACKAGE" "$VERSION")"
case "$PACKAGE_TYPE" in
declare -a fpm_dirs=(
# source dir part of 'dir' package ("/source=/dest" => "/source"):
"${PACKAGE%%=/*}"
- # backports ("llfuse==0.41.1" => "backports/python-llfuse")
+ # backports ("llfuse>=1.0" => "backports/python-llfuse")
"${WORKSPACE}/backports/${PACKAGE_TYPE}-${PACKAGE%%[<=>]*}")
if [[ -n "$PACKAGE_NAME" ]]; then
fpm_dirs+=("${WORKSPACE}/backports/${PACKAGE_NAME}")
--leave-temp Do not remove GOPATH, virtualenv, and other temp dirs at exit.
Instead, show the path to give as --temp to reuse them in
subsequent invocations.
+--repeat N Repeat each install/test step until it succeeds N times.
+--retry Prompt to retry if an install or test suite fails.
--skip-install Do not run any install steps. Just run tests.
You should provide GOPATH, GEMHOME, and VENVDIR options
from a previous invocation if you use this option.
services/crunch-run
services/crunch-dispatch-local
services/crunch-dispatch-slurm
+services/ws
sdk/cli
sdk/pam
sdk/python
sdk/go/manifest
sdk/go/blockdigest
sdk/go/streamer
+sdk/go/stats
sdk/go/crunchrunner
sdk/cwl
tools/crunchstat-summary
PERLINSTALLBASE=
short=
-skip_install=
+only_install=
temp=
temp_preserve=
echo -n 'virtualenv: '
virtualenv --version \
|| fatal "No virtualenv. Try: apt-get install virtualenv (on ubuntu: python-virtualenv)"
+ echo -n 'ruby: '
+ ruby -v \
+ || fatal "No ruby. Install >=2.1.9 (using rbenv, rvm, or source)"
+ echo -n 'bundler: '
+ bundle version \
+ || fatal "No bundler. Try: gem install bundler"
echo -n 'go: '
go version \
|| fatal "No go binary. See http://golang.org/doc/install"
exit 1
;;
--skip)
- skipwhat="$1"; shift
- if [[ "$skipwhat" == "apps/workbench" ]]; then
- skip["apps/workbench_units"]=1
- skip["apps/workbench_functionals"]=1
- skip["apps/workbench_integration"]=1
- else
- skip[$skipwhat]=1
- fi
+ skip[$1]=1; shift
;;
--only)
only="$1"; skip[$1]=""; shift
short=1
;;
--skip-install)
- skip_install=1
+ only_install=nothing
;;
--only-install)
- skip_install=1
only_install="$1"; shift
;;
--temp)
--leave-temp)
temp_preserve=1
;;
+ --repeat)
+ repeat=$((${1}+0)); shift
+ ;;
--retry)
retry=1
;;
&& eval $(python sdk/python/tests/run_test_server.py start --auth admin) \
&& export ARVADOS_TEST_API_HOST="$ARVADOS_API_HOST" \
&& export ARVADOS_TEST_API_INSTALLED="$$" \
+ && python sdk/python/tests/run_test_server.py start_ws \
+ && python sdk/python/tests/run_test_server.py start_nginx \
&& (env | egrep ^ARVADOS)
}
start_nginx_proxy_services() {
- echo 'Starting keepproxy, keep-web, arv-git-httpd, and nginx ssl proxy...'
+ echo 'Starting keepproxy, keep-web, ws, arv-git-httpd, and nginx ssl proxy...'
cd "$WORKSPACE" \
&& python sdk/python/tests/run_test_server.py start_keep_proxy \
&& python sdk/python/tests/run_test_server.py start_keep-web \
&& python sdk/python/tests/run_test_server.py start_arv-git-httpd \
+ && python sdk/python/tests/run_test_server.py start_ws \
&& python sdk/python/tests/run_test_server.py start_nginx \
&& export ARVADOS_TEST_PROXY_SERVICES=1
}
cd "$WORKSPACE" \
&& python sdk/python/tests/run_test_server.py stop_nginx \
&& python sdk/python/tests/run_test_server.py stop_arv-git-httpd \
+ && python sdk/python/tests/run_test_server.py stop_ws \
&& python sdk/python/tests/run_test_server.py stop_keep-web \
&& python sdk/python/tests/run_test_server.py stop_keep_proxy
fi
if [[ -n "$ARVADOS_TEST_API_HOST" ]]; then
unset ARVADOS_TEST_API_HOST
cd "$WORKSPACE" \
+ && python sdk/python/tests/run_test_server.py stop_nginx \
+ && python sdk/python/tests/run_test_server.py stop_ws \
&& python sdk/python/tests/run_test_server.py stop
fi
}
|| pip install --pre --ignore-installed https://github.com/curoverse/libcloud/archive/apache-libcloud-$LIBCLOUD_PIN.zip >/dev/null \
|| fatal "pip install apache-libcloud failed"
-# This will help people who reuse --temp dirs when we upgrade to llfuse 0.42
-if egrep -q 'llfuse.*>= *0\.42' "$WORKSPACE/services/fuse/setup.py"; then
- # Uninstall old llfuse, because services/fuse "pip install" won't
- # upgrade it by default.
- if pip freeze | egrep '^llfuse==0\.41\.'; then
- yes | pip uninstall 'llfuse<0.42'
- fi
+# Uninstall old llfuse (<1.0), because services/fuse "pip install"
+# won't upgrade it by default.
+if pip freeze | egrep '^llfuse==0'; then
+ yes | pip uninstall 'llfuse<1.0'
fi
# Deactivate Python 2 virtualenv
fi
retry() {
- while ! ${@} && [[ "$retry" == 1 ]]
+ remain="${repeat}"
+ while :
do
- read -p 'Try again? [Y/n] ' x
- if [[ "$x" != "y" ]] && [[ "$x" != "" ]]
- then
+ if ${@}; then
+ if [[ "$remain" -gt 1 ]]; then
+ remain=$((${remain}-1))
+ title "Repeating ${remain} more times"
+ else
+ break
+ fi
+ elif [[ "$retry" == 1 ]]; then
+ read -p 'Try again? [Y/n] ' x
+ if [[ "$x" != "y" ]] && [[ "$x" != "" ]]
+ then
+ break
+ fi
+ else
break
fi
done
}
do_test() {
- retry do_test_once ${@}
+ case "${1}" in
+ apps/workbench_units | apps/workbench_functional | apps/workbench_integration)
+ suite=apps/workbench
+ ;;
+ *)
+ suite="${1}"
+ ;;
+ esac
+ if [[ -z "${skip[$suite]}" && -z "${skip[$1]}" && \
+ (-z "${only}" || "${only}" == "${suite}" || \
+ "${only}" == "${1}") ]]; then
+ retry do_test_once ${@}
+ else
+ title "Skipping ${1} tests"
+ fi
}
do_test_once() {
unset result
- to_test=$1
- if (( [[ "$only" == "apps/workbench" ]] ) &&
- ( [[ "$to_test" == "apps/workbench_units" ]] || [[ "$to_test" == "apps/workbench_functionals" ]] ||
- [[ "$to_test" == "apps/workbench_integration" ]])); then
- to_test="apps/workbench"
- fi
- if [[ -z "${skip[$1]}" ]] && ( [[ -z "$only" ]] || [[ "$only" == "$to_test" ]] )
+
+ title "Running $1 tests"
+ timer_reset
+ if [[ "$2" == "go" ]]
then
- title "Running $1 tests"
- timer_reset
- if [[ "$2" == "go" ]]
- then
- covername="coverage-$(echo "$1" | sed -e 's/\//_/g')"
- coverflags=("-covermode=count" "-coverprofile=$WORKSPACE/tmp/.$covername.tmp")
- # We do "go get -t" here to catch compilation errors
- # before trying "go test". Otherwise, coverage-reporting
- # mode makes Go show the wrong line numbers when reporting
- # compilation errors.
- go get -t "git.curoverse.com/arvados.git/$1" || return 1
- cd "$WORKSPACE/$1" || return 1
- gofmt -e -d . | egrep . && result=1
- if [[ -n "${testargs[$1]}" ]]
- then
- # "go test -check.vv giturl" doesn't work, but this
- # does:
- cd "$WORKSPACE/$1" && go test ${short:+-short} ${testargs[$1]}
- else
- # The above form gets verbose even when testargs is
- # empty, so use this form in such cases:
- go test ${short:+-short} ${coverflags[@]} "git.curoverse.com/arvados.git/$1"
- fi
- result=${result:-$?}
- if [[ -f "$WORKSPACE/tmp/.$covername.tmp" ]]
- then
- go tool cover -html="$WORKSPACE/tmp/.$covername.tmp" -o "$WORKSPACE/tmp/$covername.html"
- rm "$WORKSPACE/tmp/.$covername.tmp"
- fi
- elif [[ "$2" == "pip" ]]
+ covername="coverage-$(echo "$1" | sed -e 's/\//_/g')"
+ coverflags=("-covermode=count" "-coverprofile=$WORKSPACE/tmp/.$covername.tmp")
+ # We do "go get -t" here to catch compilation errors
+ # before trying "go test". Otherwise, coverage-reporting
+ # mode makes Go show the wrong line numbers when reporting
+ # compilation errors.
+ go get -t "git.curoverse.com/arvados.git/$1" || return 1
+ cd "$WORKSPACE/$1" || return 1
+ gofmt -e -d . | egrep . && result=1
+ if [[ -n "${testargs[$1]}" ]]
then
- tries=0
- cd "$WORKSPACE/$1" && while :
- do
- tries=$((${tries}+1))
- # $3 can name a path directory for us to use, including trailing
- # slash; e.g., the bin/ subdirectory of a virtualenv.
- "${3}python" setup.py ${short:+--short-tests-only} test ${testargs[$1]}
- result=$?
- if [[ ${tries} < 3 && ${result} == 137 ]]
- then
- printf '\n*****\n%s tests killed -- retrying\n*****\n\n' "$1"
- continue
- else
- break
- fi
- done
- elif [[ "$2" != "" ]]
- then
- "test_$2"
+ # "go test -check.vv giturl" doesn't work, but this
+ # does:
+ cd "$WORKSPACE/$1" && go test ${short:+-short} ${testargs[$1]}
else
- "test_$1"
+ # The above form gets verbose even when testargs is
+ # empty, so use this form in such cases:
+ go test ${short:+-short} ${coverflags[@]} "git.curoverse.com/arvados.git/$1"
fi
result=${result:-$?}
- checkexit $result "$1 tests"
- title "End of $1 tests (`timer`)"
- return $result
+ if [[ -f "$WORKSPACE/tmp/.$covername.tmp" ]]
+ then
+ go tool cover -html="$WORKSPACE/tmp/.$covername.tmp" -o "$WORKSPACE/tmp/$covername.html"
+ rm "$WORKSPACE/tmp/.$covername.tmp"
+ fi
+ elif [[ "$2" == "pip" ]]
+ then
+ tries=0
+ cd "$WORKSPACE/$1" && while :
+ do
+ tries=$((${tries}+1))
+ # $3 can name a path directory for us to use, including trailing
+ # slash; e.g., the bin/ subdirectory of a virtualenv.
+ "${3}python" setup.py ${short:+--short-tests-only} test ${testargs[$1]}
+ result=$?
+ if [[ ${tries} < 3 && ${result} == 137 ]]
+ then
+ printf '\n*****\n%s tests killed -- retrying\n*****\n\n' "$1"
+ continue
+ else
+ break
+ fi
+ done
+ elif [[ "$2" != "" ]]
+ then
+ "test_$2"
else
- title "Skipping $1 tests"
+ "test_$1"
fi
+ result=${result:-$?}
+ checkexit $result "$1 tests"
+ title "End of $1 tests (`timer`)"
+ return $result
}
do_install() {
- retry do_install_once ${@}
+ if [[ -z "${only_install}" || "${only_install}" == "${1}" ]]; then
+ retry do_install_once ${@}
+ else
+ title "Skipping $1 install"
+ fi
}
do_install_once() {
- if [[ -z "$skip_install" || (-n "$only_install" && "$only_install" == "$1") ]]
+ title "Running $1 install"
+ timer_reset
+ if [[ "$2" == "go" ]]
then
- title "Running $1 install"
- timer_reset
- if [[ "$2" == "go" ]]
- then
- go get -t "git.curoverse.com/arvados.git/$1"
- elif [[ "$2" == "pip" ]]
- then
- # $3 can name a path directory for us to use, including trailing
- # slash; e.g., the bin/ subdirectory of a virtualenv.
-
- # Need to change to a different directory after creating
- # the source dist package to avoid a pip bug.
- # see https://arvados.org/issues/5766 for details.
-
- # Also need to install twice, because if it believes the package is
- # already installed, pip it won't install it. So the first "pip
- # install" ensures that the dependencies are met, the second "pip
- # install" ensures that we've actually installed the local package
- # we just built.
- cd "$WORKSPACE/$1" \
- && "${3}python" setup.py sdist rotate --keep=1 --match .tar.gz \
- && cd "$WORKSPACE" \
- && "${3}pip" install --quiet "$WORKSPACE/$1/dist"/*.tar.gz \
- && "${3}pip" install --quiet --no-deps --ignore-installed "$WORKSPACE/$1/dist"/*.tar.gz
- elif [[ "$2" != "" ]]
- then
- "install_$2"
- else
- "install_$1"
- fi
- result=$?
- checkexit $result "$1 install"
- title "End of $1 install (`timer`)"
- return $result
+ go get -t "git.curoverse.com/arvados.git/$1"
+ elif [[ "$2" == "pip" ]]
+ then
+ # $3 can name a path directory for us to use, including trailing
+ # slash; e.g., the bin/ subdirectory of a virtualenv.
+
+ # Need to change to a different directory after creating
+ # the source dist package to avoid a pip bug.
+ # see https://arvados.org/issues/5766 for details.
+
+ # Also need to install twice, because if it believes the package is
+ # already installed, pip it won't install it. So the first "pip
+ # install" ensures that the dependencies are met, the second "pip
+ # install" ensures that we've actually installed the local package
+ # we just built.
+ cd "$WORKSPACE/$1" \
+ && "${3}python" setup.py sdist rotate --keep=1 --match .tar.gz \
+ && cd "$WORKSPACE" \
+ && "${3}pip" install --quiet "$WORKSPACE/$1/dist"/*.tar.gz \
+ && "${3}pip" install --quiet --no-deps --ignore-installed "$WORKSPACE/$1/dist"/*.tar.gz
+ elif [[ "$2" != "" ]]
+ then
+ "install_$2"
else
- title "Skipping $1 install"
+ "install_$1"
fi
+ result=$?
+ checkexit $result "$1 install"
+ title "End of $1 install (`timer`)"
+ return $result
}
bundle_install_trylocal() {
sdk/go/manifest
sdk/go/streamer
sdk/go/crunchrunner
+ sdk/go/stats
lib/crunchstat
services/arv-git-httpd
services/crunchstat
sdk/go/keepclient
services/keep-balance
services/keepproxy
- services/datamanager/summary
- services/datamanager/collection
- services/datamanager/keep
- services/datamanager
services/crunch-dispatch-local
services/crunch-dispatch-slurm
services/crunch-run
+ services/ws
tools/keep-block-check
tools/keep-exercise
tools/keep-rsync
- Welcome:
- user/index.html.textile.liquid
- user/getting_started/community.html.textile.liquid
- - Run a pipeline using Workbench:
+ - Run a workflow using Workbench:
- user/getting_started/workbench.html.textile.liquid
- - user/tutorials/tutorial-pipeline-workbench.html.textile.liquid
+ - user/tutorials/tutorial-workflow-workbench.html.textile.liquid
- Access an Arvados virtual machine:
- user/getting_started/vm-login-with-webshell.html.textile.liquid
- user/getting_started/ssh-access-unix.html.textile.liquid
- user/tutorials/tutorial-keep-mount.html.textile.liquid
- user/topics/keep.html.textile.liquid
- user/topics/arv-copy.html.textile.liquid
- - Using Common Workflow Language:
+ - Running workflows at the command line:
- user/cwl/cwl-runner.html.textile.liquid
- - user/cwl/cwl-style.html.textile.liquid
- - Working on the command line:
+ - user/cwl/cwl-run-options.html.textile.liquid
- user/topics/running-pipeline-command-line.html.textile.liquid
- user/topics/arv-run.html.textile.liquid
- Working with git repositories:
- user/tutorials/add-new-repository.html.textile.liquid
- user/tutorials/git-arvados-guide.html.textile.liquid
- - Develop an Arvados pipeline:
+ - Develop an Arvados workflow:
- user/tutorials/intro-crunch.html.textile.liquid
+ - user/tutorials/writing-cwl-workflow.html.textile.liquid
+ - user/cwl/cwl-style.html.textile.liquid
+ - user/cwl/cwl-extensions.html.textile.liquid
+ - user/topics/arv-docker.html.textile.liquid
- user/tutorials/running-external-program.html.textile.liquid
- user/topics/crunch-tools-overview.html.textile.liquid
- user/tutorials/tutorial-firstscript.html.textile.liquid
- user/tutorials/tutorial-submit-job.html.textile.liquid
- user/topics/tutorial-parallel.html.textile.liquid
- - user/topics/arv-docker.html.textile.liquid
- Develop a web service:
- user/topics/arv-web.html.textile.liquid
- Reference:
- sdk/index.html.textile.liquid
- Python:
- sdk/python/sdk-python.html.textile.liquid
+ - sdk/python/example.html.textile.liquid
- sdk/python/python.html.textile.liquid
- sdk/python/crunch-utility-libraries.html.textile.liquid
- sdk/python/events.html.textile.liquid
+ - CLI:
+ - sdk/cli/install.html.textile.liquid
+ - sdk/cli/index.html.textile.liquid
+ - sdk/cli/reference.html.textile.liquid
+ - sdk/cli/subcommands.html.textile.liquid
+ - Go:
+ - sdk/go/index.html.textile.liquid
+ - sdk/go/example.html.textile.liquid
- Perl:
- sdk/perl/index.html.textile.liquid
+ - sdk/perl/example.html.textile.liquid
- Ruby:
- sdk/ruby/index.html.textile.liquid
+ - sdk/ruby/example.html.textile.liquid
- Java:
- sdk/java/index.html.textile.liquid
- - Go:
- - sdk/go/index.html.textile.liquid
- - CLI:
- - sdk/cli/index.html.textile.liquid
- - sdk/cli/install.html.textile.liquid
- - sdk/cli/reference.html.textile.liquid
- - sdk/cli/subcommands.html.textile.liquid
+ - sdk/java/example.html.textile.liquid
api:
- Concepts:
- api/index.html.textile.liquid
- - api/authentication.html.textile.liquid
+ - api/tokens.html.textile.liquid
+ - api/requests.html.textile.liquid
- api/methods.html.textile.liquid
- api/resources.html.textile.liquid
- - api/crunch-scripts.html.textile.liquid
- api/permission-model.html.textile.liquid
- - API Methods:
+ - api/storage.html.textile.liquid
+ - api/execution.html.textile.liquid
+ - Permission and authentication:
- api/methods/api_client_authorizations.html.textile.liquid
- api/methods/api_clients.html.textile.liquid
- api/methods/authorized_keys.html.textile.liquid
- - api/methods/collections.html.textile.liquid
- - api/methods/container_requests.html.textile.liquid
- - api/methods/containers.html.textile.liquid
- api/methods/groups.html.textile.liquid
- - api/methods/humans.html.textile.liquid
- - api/methods/jobs.html.textile.liquid
- - api/methods/job_tasks.html.textile.liquid
- - api/methods/keep_disks.html.textile.liquid
+ - api/methods/users.html.textile.liquid
+ - System resources:
- api/methods/keep_services.html.textile.liquid
- api/methods/links.html.textile.liquid
- api/methods/logs.html.textile.liquid
- api/methods/nodes.html.textile.liquid
+ - api/methods/virtual_machines.html.textile.liquid
+ - api/methods/keep_disks.html.textile.liquid
+ - Data management:
+ - api/methods/collections.html.textile.liquid
+ - api/methods/repositories.html.textile.liquid
+ - Container engine:
+ - api/methods/container_requests.html.textile.liquid
+ - api/methods/containers.html.textile.liquid
+ - api/methods/workflows.html.textile.liquid
+ - Jobs engine (deprecated):
+ - api/crunch-scripts.html.textile.liquid
+ - api/methods/jobs.html.textile.liquid
+ - api/methods/job_tasks.html.textile.liquid
- api/methods/pipeline_instances.html.textile.liquid
- api/methods/pipeline_templates.html.textile.liquid
- - api/methods/repositories.html.textile.liquid
+ - Metadata for bioinformatics:
+ - api/methods/humans.html.textile.liquid
- api/methods/specimens.html.textile.liquid
- api/methods/traits.html.textile.liquid
- - api/methods/users.html.textile.liquid
- - api/methods/virtual_machines.html.textile.liquid
- - api/methods/workflows.html.textile.liquid
- - Schema:
- - api/schema/ApiClientAuthorization.html.textile.liquid
- - api/schema/ApiClient.html.textile.liquid
- - api/schema/AuthorizedKey.html.textile.liquid
- - api/schema/Collection.html.textile.liquid
- - api/schema/Container.html.textile.liquid
- - api/schema/ContainerRequest.html.textile.liquid
- - api/schema/Group.html.textile.liquid
- - api/schema/Human.html.textile.liquid
- - api/schema/Job.html.textile.liquid
- - api/schema/JobTask.html.textile.liquid
- - api/schema/KeepDisk.html.textile.liquid
- - api/schema/KeepService.html.textile.liquid
- - api/schema/Link.html.textile.liquid
- - api/schema/Log.html.textile.liquid
- - api/schema/Node.html.textile.liquid
- - api/schema/PipelineInstance.html.textile.liquid
- - api/schema/PipelineTemplate.html.textile.liquid
- - api/schema/Repository.html.textile.liquid
- - api/schema/Specimen.html.textile.liquid
- - api/schema/Trait.html.textile.liquid
- - api/schema/User.html.textile.liquid
- - api/schema/VirtualMachine.html.textile.liquid
- - api/schema/Workflow.html.textile.liquid
installguide:
- Overview:
- install/index.html.textile.liquid
- install/configure-azure-blob-storage.html.textile.liquid
- install/install-keepproxy.html.textile.liquid
- install/install-keep-web.html.textile.liquid
- - Install Crunch v2 on SLURM:
+ - Containers API support on SLURM:
- install/crunch2-slurm/install-prerequisites.html.textile.liquid
- install/crunch2-slurm/install-compute-node.html.textile.liquid
- install/crunch2-slurm/install-dispatch.html.textile.liquid
- install/crunch2-slurm/install-test.html.textile.liquid
- - Install Crunch v1:
+ - Jobs API support (deprecated):
- install/install-crunch-dispatch.html.textile.liquid
- install/install-compute-node.html.textile.liquid
- Helpful hints:
|vcpus|integer|Number of cores to be used to run this process.|Optional. However, a ContainerRequest that is in "Committed" state must provide this.|
|keep_cache_ram|integer|Number of keep cache bytes to be used to run this process.|Optional.|
|API|boolean|When set, ARVADOS_API_HOST and ARVADOS_API_TOKEN will be set, and container will have networking enabled to access the Arvados API server.|Optional.|
-|partition|array of strings|Specify the names of one or more compute partitions that may run this container. If not provided, the system chooses where to run the container.|Optional.|
--- /dev/null
+Scheduling parameters
+
+Parameters to be passed to the container scheduler (e.g., SLURM) when running a container.
+
+table(table table-bordered table-condensed).
+|_. Key|_. Type|_. Description|_. Notes|
+|partitions|array of strings|The names of one or more compute partitions that may run this container. If not provided, the system will choose where to run the container.|Optional.|
--- /dev/null
+{% include 'notebox_begin_warning' %}
+This section assumes the legacy Jobs API is available. Some newer installations have already disabled the Jobs API in favor of the Containers API.
--- /dev/null
+{% include 'notebox_end' %}
--- /dev/null
+<div class="alert alert-block alert-warning">
+ <h4>Note:</h4>
-{% include 'notebox_begin' %}
+{% include 'notebox_begin_warning' %}
Arvados pipeline templates are deprecated. The recommended way to develop new workflows for Arvados is using the "Common Workflow Language":{{site.baseurl}}/user/cwl/cwl-runner.html.
{% include 'notebox_end' %}
--- /dev/null
+The "Common Workflow Language (CWL)":http://commonwl.org is a multi-vendor open standard for describing analysis tools and workflows that are portable across a variety of platforms. CWL is the recommended way to develop and run workflows for Arvados. Arvados supports the "CWL v1.0":http://commonwl.org/v1.0 specification.
<html>
<head>
<meta charset="utf-8">
- <title>{% unless page.title == "Arvados | Documentation" %} Arvados | Documentation | {% endunless %}{{ page.title }}</title>
+ <title>{% unless page.title == "Arvados | Documentation" %} Arvados {% if page.navmenu %}| {{ page.navmenu }} {% endif %} | {% endunless %}{{ page.title }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Concepts
-title: Authentication
-
-...
-
-
-
-Every API request (except the authentication API itself) includes an @access_token@ parameter.
-
-table(table table-bordered table-condensed).
-|Name|Type|Description|
-|access_token|string|Access token returned by OAuth 2.0 authorization procedure|
-
-Many resources contain "actor" attributes like @modified_by@. An @access_token@ uniquely identifies a client (application or project) and an end-user.
-
-table(table table-bordered table-condensed).
-|Name|Type|Description|
-|modified_by_client_uuid|string|ID of API client|
-|modified_by_user_uuid|string|ID of authenticated user|
-
-h2. Authorizing a client application
-
-The Arvados API uses the "OAuth 2.0 protocol":http://tools.ietf.org/html/draft-ietf-oauth-v2-22 for authentication and authorization.
-
-h3. Register your client application
-
-Before an application can run on an Arvados cloud, it needs to be registered with the cloud.
-
-That registration yields a @client_id@ and a @client_secret@.
-
-h3. Obtain an access code
-
-A client obtains an access code by means of a standard Oauth 2.0 flow. The access code is granted to it by an authorized user. The client requests one or more scopes, which translate to a set of requested permissions (reading, writing, etc). Unless the access is to be short-lived, a refresh token is also granted to the application.
-
-h3. Refresh the access code (optional)
-
-Access codes have a limited lifetime. A refresh token allows an application to request a new access token.
table(table table-bordered table-condensed).
|Environment variable|Description|
-|@JOB_UUID@|UUID of the current "Job":schema/Job.html|
-|@TASK_UUID@|UUID of the current "JobTask":schema/JobTask.html|
+|@JOB_UUID@|UUID of the current "Job":methods/jobs.html|
+|@TASK_UUID@|UUID of the current "JobTask":methods/job_tasks.html|
|@ARVADOS_API_HOST@|Hostname and port number of API server|
|@ARVADOS_API_TOKEN@|Authentication token to use with API calls made by the current task|
$sys.stderr.write("current task sequence number is %d"
% task['sequence'])
</pre>
-
--- /dev/null
+---
+layout: default
+navsection: api
+title: Computing with Crunch
+...
+
+Crunch is the name for the Arvados system for managing computation. It provides an abstract API to various clouds and HPC resource allocation and scheduling systems, and integrates closely with Keep storage and the Arvados permission system.
+
+h2. Container API
+
+Note: although the preferred API for Arvados going forward, the Container API may not yet be available on all installations.
+
+# To submit work, create a "container request":{{site.baseurl}}/api/methods/container_requests.html in the @Committed@ state.
+# The system will fufill the container request by creating or reusing a "Container object":{{site.baseurl}}/api/methods/containers.html and assigning it to the @container_uuid@ field. If the same request has been submitted in the past, it may reuse an existing container. The reuse behavior can be suppressed with @use_existing: false@ in the container request.
+# The dispatcher process will notice a new container in @Queued@ state and submit a container executor to the underlying work queuing system (such as SLURM).
+# The container executes. Upon termination the container goes into the @Complete@ state. If the container execution was interrupted or lost due to system failure, it will go into the @Cancelled@ state.
+# When the container associated with the container request is completed, the container request will go into the @Final@ state.
+# The @output_uuid@ field of the container request contains the uuid of output collection produced by container request.
+
+!{{site.baseurl}}/images/Crunch_dispatch.svg!
+
+h2. Job API (deprecated)
+
+# To submit work, create a "job":{{site.baseurl}}/api/methods/jobs.html . If the same job has been submitted in the past, it will return an existing job in @Completed@ state.
+# The dispatcher process will notice a new job in @Queued@ state and attempt to allocate nodes to run the job.
+# The job executes.
+# Retrieve the @output@ field with the portable data hash of the collection with the output files of the job.
...
+This reference describes the semantics of Arvados resources and how to programatically access Arvados via its REST API. Each resource listed in this section is exposed on the Arvados API server under the @/arvados/v1/@ path prefix, for example, @https://{{ site.arvados_api_host }}/arvados/v1/collections@.
+h2. Discovery document
-h2. Concepts
+The API server publishes a machine-readable description of its endpoints and some additional site configuration values via a JSON-formatted discovery document. This is available at @/discovery/v1/apis/arvados/v1/rest@, for example @https://{{ site.arvados_api_host }}/discovery/v1/apis/arvados/v1/rest@. Some Arvados SDKs use the discovery document to generate language bindings.
-* Each API uses the same "authentication mechanism":authentication.html.
-* Resources in requests and responses adhere to a "common structure":resources.html.
-* API transactions use common "REST methods":methods.html.
-* API transactions are subject to a "permission model":permission-model.html.
-* "Job tasks":schema/JobTask.html use some special API features.
+h2. Workbench examples
-h2. Resources
-
-h3. Generic Resources
-
-* "Collection":schema/Collection.html
-* "Job":schema/Job.html
-* "JobTask":schema/JobTask.html
-* "Link":schema/Link.html
-* "Log":schema/Log.html
-* "PipelineTemplate":schema/PipelineTemplate.html
-* "PipelineInstance":schema/PipelineInstance.html
-* "Group":schema/Group.html
-* "Human":schema/Human.html
-* "Specimen":schema/Specimen.html
-* "Trait":schema/Trait.html
-* "User":schema/User.html
-
-h3. Authentication
-
-These Arvados resources govern authorization and "authentication":authentication.html:
-
-* "ApiClient":schema/ApiClient.html
-* "ApiClientAuthorization":schema/ApiClientAuthorization.html
-* "AuthorizedKey":schema/AuthorizedKey.html
-
-h3. Arvados Infrastructure
-
-These resources govern the Arvados infrastructure itself: Git repositories, Keep disks, active nodes, etc.
-
-* "KeepDisk":schema/KeepDisk.html
-* "Node":schema/Node.html
-* "Repository":schema/Repository.html
-* "VirtualMachine":schema/VirtualMachine.html
+Many Arvados Workbench pages, under the the *Advanced* tab, provide examples of API and SDK use for accessing the current resource .
layout: default
navsection: api
navmenu: Concepts
-title: REST methods
+title: Common resource methods
...
+The following methods are available for most resources. Some resources may limit who can perform certain operations. Consult documentation for individual resource types for details.
+The methods are relative to the base URI, e.g. @/arvados/v1/resource_type@. For arguments specifying a *Location* of @path@, the value of the argument is incorporated into the path portion of the URI. For example, a @uuid@ of @aaaaa-bbbbb-ccccccccccccccc@ in a path position yields a URI of @/arvados/v1/resource_type/aaaaa-bbbbb-ccccccccccccccc@.
-(using Group as an example)
+Arguments specifying a *Location* of @query@ are incorporated into the query portion of the URI or request body. For example, @/arvados/v1/resource_type?resource_type={}@.
-h2(#index). Index, list, search
+h2. create
-<pre>
-GET https://{{ site.arvados_api_host }}/arvados/v1/groups?filters=[["owner_uuid","=","xyzzy-tpzed-a4lcehql0dv2u25"]]
+The @create@ method creates a new object of the specified type. Note that:
-POST https://{{ site.arvados_api_host }}/arvados/v1/groups
-_method=GET
-filters=[["owner_uuid","=","xyzzy-tpzed-a4lcehql0dv2u25"]]
-</pre>
+* Only the listed attributes (and "standard metadata":resources.html) are set
+* Unset attributes will get default values
+* The attributes of a given resource type are fixed (you cannot introduce new toplevel attributes)
-→ Group resource list
+This method corresponds to the HTTP request @POST /arvados/v1/resource_type@. A successful create call returns a copy of the new object.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |
+|{resource_type}|object|Name is the singular form of the resource type, e.g. for the "collections" resource, this argument is "collection"|query||
+
+h2. delete
+
+The @delete@ method deletes an object of the specified type. It corresponds to the HTTP request @DELETE /arvados/v1/resource_type/uuid@. A successful delete call returns a copy of the deleted object.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |
+{background:#ccffcc}.|uuid|string|The UUID of the object in question.|path|
+
+h2. get
+
+The @get@ method gets a single object with the specified @uuid@. It corresponds to the HTTP request @GET /arvados/v1/resource_type/uuid@.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |
+{background:#ccffcc}.|uuid|string|The UUID of the object in question.|path|
+
+h2(#index). list
+
+The @list@ method requests an list of resources of that type. It corresponds to the HTTP request @GET /arvados/v1/resource_type@. All resources support "list" method unless otherwise noted.
+
+Arguments:
table(table table-bordered table-condensed).
-|*Parameter name*|*Value*|*Description*|
-|limit |integer|Maximum number of resources to return.|
-|offset |integer|Skip the first 'offset' resources that match the given filter conditions.|
-|filters |array |Conditions for selecting resources to return (see below).|
+|_. Argument |_. Type |_. Description |_. Location |
+|limit |integer|Maximum number of resources to return. If not provided, server will provide a default limit. Server may also impose a maximum number of records that can be returned in a single request.|query|
+|offset |integer|Skip the first 'offset' number of resources that would be returned under the given filter conditions.|query|
+|filters |array |"Conditions for selecting resources to return.":#filters|query|
|order |array |Attributes to use as sort keys to determine the order resources are returned, each optionally followed by @asc@ or @desc@ to indicate ascending or descending order.
Example: @["head_uuid asc","modified_at desc"]@
-Default: @["created_at desc"]@|
+Default: @["created_at desc"]@|query|
|select |array |Set of attributes to include in the response.
Example: @["head_uuid","tail_uuid"]@
-Default: all available attributes, minus "manifest_text" in the case of collections.|
+Default: all available attributes. As a special case, collections do not return "manifest_text" unless explicitly selected.|query|
|distinct|boolean|@true@: (default) do not return duplicate objects
-@false@: permitted to return duplicates|
+@false@: permitted to return duplicates|query|
-h3. Filters
+h3(#filters). Available list method filters
The value of the @filters@ parameter is an array of conditions. The @list@ method returns only the resources that satisfy all of the given conditions. In other words, the conjunction @AND@ is implicit.
|@in@, @not in@|array of strings|@["script_version","in",["master","d00220fb38d4b85ca8fc28a8151702a2b9d1dec5"]]@|
|@is_a@|string|@["head_uuid","is_a","arvados#pipelineInstance"]@|
-h2. Create
-
-<pre>
-POST https://{{ site.arvados_api_host }}/arvados/v1/groups
-group={"name":"fresh new group"}
-</pre>
-
-→ Group resource
-
-h2. Delete
-
-<pre>
-DELETE https://{{ site.arvados_api_host }}/arvados/v1/groups/xyzzy-ldvyl-vyydjeplwaa6emg
-</pre>
+h3. Results of list method
-→ Group resource
+A successful call to list will return the following object.
-h2. Update
-
-<pre>
-PUT https://{{ site.arvados_api_host }}/arvados/v1/groups/xyzzy-ldvyl-vyydjeplwaa6emg
-group={"uuid":"xyzzy-ldvyl-vyydjeplwaa6emg", "name":"Important group"}
-</pre>
-
-→ Group resource
-
-<pre>
-PUT https://{{ site.arvados_api_host }}/arvados/v1/groups/xyzzy-ldvyl-vyydjeplwaa6emg
-group[uuid]=xyzzy-ldvyl-vyydjeplwaa6emg
-group[name]=Important group
-</pre>
-
-→ Group resource
+table(table table-bordered table-condensed).
+|_. Attribute |_. Type |_. Description |
+|kind|string|type of objects returned|
+|offset|integer|query offset in effect|
+|limit|integer|query limit in effect|
+|items|array|actual query payload, an array of resource objects|
+|items_available|integer|total items available matching query|
-More appropriate (but not yet implemented):
+h2. update
-<pre>
-PATCH https://{{ site.arvados_api_host }}/arvados/v1/groups/xyzzy-ldvyl-vyydjeplwaa6emg
-group={"uuid":"xyzzy-ldvyl-vyydjeplwaa6emg", "name":"Important group"}
-</pre>
+The @update@ method updates fields on the object with the specified @uuid@. It corresponds to the HTTP request @PUT /arvados/v1/resource_type/uuid@. Note that only the listed attributes (and "standard metadata":resources.html) are updated, unset attributes will retain their previous values, and the attributes of a given resource type are fixed (you cannot introduce new toplevel attributes). Also note that updates replace the value of the attribute, so if an attribute has an object value, the entire object is replaced. A successful update call returns the updated copy of the object.
-→ Group resource
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |
+{background:#ccffcc}.|uuid|string|The UUID of the resource in question.|path||
+|{resource_type}|object||query||
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/api_client_authorizations@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @gj3su@
+
+Example UUID: @zzzzz-gj3su-0123456789abcde@
+
+h2. Resource
+
+The @api_client_authorizations@ resource stores the API tokens that have been issued to permit access the API server.
+
+An ApiClientAuthorization is *not* a generic Arvados resource. The full list of properties that belong to an ApiClientAuthorization is:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|uuid|string|An identifier used to refer to the token without exposing the actual token.||
+|api_token|string|The actual token string that is expected in the Authorization header.||
+|api_client_id|integer|-||
+|user_id|integer|-||
+|created_by_ip_address|string|-||
+|last_used_by_ip_address|string|The network address of the most recent client using this token.||
+|last_used_at|datetime|Timestamp of the most recent request using this token.||
+|expires_at|datetime|Time at which the token is no longer valid. May be set to a time in the past in order to immediately expire a token.||
+|owner_uuid|string|The user associated with the token. All operations using this token are checked against the permissions of this user.||
+|scopes|array|A list of resources this token is allowed to access. A scope of ["all"] allows all resources. See "API Authorization":{{site.baseurl}}/api/tokens.html#scopes for details.||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3(#create). create
Create a new ApiClientAuthorization.
+Regular users may only create self-owned API tokens, but may provide a restricted "scope":{{site.baseurl}}/api/tokens.html#scopes . Administrators may create API tokens corresponding to any user.
+
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|api_client_authorization|object||query||
-h2. create_system_auth
+h3. create_system_auth
create_system_auth api_client_authorizations
|api_client_id|integer||query||
|scopes|array||query||
-h2. delete
+h3. delete
Delete an existing ApiClientAuthorization.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the ApiClientAuthorization in question.|path||
-h2. get
+h3. get
-Gets a ApiClientAuthorization's metadata by UUID.
+Gets an ApiClientAuthorization's metadata by UUID.
Arguments:
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the ApiClientAuthorization in question.|path||
-h2. list
+h3. list
List api_client_authorizations.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of api_client_authorizations to return.|query||
-|order|string|Order in which to return matching api_client_authorizations.|query||
-|filters|array|Conditions for filtering api_client_authorizations.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing ApiClientAuthorization.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/api_clients@
+Object type: @ozdt8@
+
+Example UUID: @zzzzz-ozdt8-0123456789abcde@
+
+h2. Resource
+
+The "api_clients" resource determines if web applications that have gone through the browser login flow may create or list API tokens.
+
+Each ApiClient has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|||
+|url_prefix|string|||
+|is_trusted|boolean|Trusted by users to handle their API tokens (ApiClientAuthorizations).||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new ApiClient.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|api_client|object||query||
-h2. delete
+h3. delete
Delete an existing ApiClient.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the ApiClient in question.|path||
-h2. get
+h3. get
Gets a ApiClient's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the ApiClient in question.|path||
-h2. list
+h3. list
List api_clients.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of api_clients to return.|query||
-|order|string|Order in which to return matching api_clients.|query||
-|filters|array|Conditions for filtering api_clients.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing ApiClient.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/authorized_keys@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @fngyi@
+
+Example UUID: @zzzzz-fngyi-0123456789abcde@
+
+h2. Resource
+
+The authorized_keys resource stores SSH public keys which grant access to virtual machines or git repositories on the Arvados cluster as the user in @authorized_user_uuid@.
+
+Each AuthorizedKey has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|A name to help the user manage their keys.||
+|key_type|string|Public key type, currently only supports "SSH"||
+|authorized_user_uuid|string|The user to which this key belongs. Authentication using this key authenticates as this user.||
+|public_key|text|The actual public key material, e.g. from @~/.ssh/id_rsa.pub@||
+|expires_at|datetime|Expiration date after which the key is no longer valid.||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new AuthorizedKey.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|authorized_key|object||query||
-h2. delete
+h3. delete
Delete an existing AuthorizedKey.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the AuthorizedKey in question.|path||
-h2. get
+h3. get
Gets a AuthorizedKey's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the AuthorizedKey in question.|path||
-h2. list
+h3. list
List authorized_keys.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of authorized_keys to return.|query||
-|order|string|Order in which to return matching authorized_keys.|query||
-|filters|array|Conditions for filtering authorized_keys.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing AuthorizedKey.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/collections@
+Object type: @4zz18@
+
+Example UUID: @zzzzz-4zz18-0123456789abcde@
+
+h2. Resource
+
+Collections describe sets of files in terms of data blocks stored in Keep. See "storage in Keep":{{site.baseurl}}/api/storage.html for details.
+
+Each collection has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|||
+|description|text|||
+|portable_data_hash|string|The MD5 sum of the manifest text stripped of block hints other than the size hint.||
+|manifest_text|text|||
+|replication_desired|number|Minimum storage replication level desired for each data block referenced by this collection. A value of @null@ signifies that the site default replication level (typically 2) is desired.|@2@|
+|replication_confirmed|number|Replication level most recently confirmed by the storage system. This field is null when a collection is first created, and is reset to null when the manifest_text changes in a way that introduces a new data block. An integer value indicates the replication level of the _least replicated_ data block in the collection.|@2@, null|
+|replication_confirmed_at|datetime|When replication_confirmed was confirmed. If replication_confirmed is null, this field is also null.||
+
+h3. Conditions of creating a Collection
+
+The @portable_data_hash@ and @manifest_text@ attributes must be provided when creating a Collection. The cryptographic digest of the supplied @manifest_text@ must match the supplied @portable_data_hash@.
+
+h3. Side effects of creating a Collection
+
+Referenced blocks are protected from garbage collection in Keep.
+
+Data can be shared with other users via the Arvados permission model.
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new Collection.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|collection|object||query||
-h2. delete
+h3. delete
Delete an existing Collection.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Collection in question.|path||
-h2. get
+h3. get
Gets a Collection's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Collection in question.|path||
-h2. list
+h3. list
List collections.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of collections to return.|query||
-|order|string|Order in which to return matching collections.|query||
-|filters|array|Conditions for filtering collections.|query||
-|select|array|Data fields to return in the result list.|query|@["uuid", "manifest_text"]@|
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
Note: Because adding access tokens to manifests can be computationally expensive, the @manifest_text@ field is not included in results by default. If you need it, pass a @select@ parameter that includes @manifest_text@.
-h2. update
+h3. update
Update attributes of an existing Collection.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/container_requests@
+Object type: @xvhdp@
+
+Example UUID: @zzzzz-xvhdp-0123456789abcde@
+
+h2. Resource
+
+A container request is a request for the Arvados cluster to perform some computational work. See "computing with Crunch":{{site.baseurl}}/api/execution.html for details.
+
+Each ContainerRequest offers the following attributes, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+All attributes are optional, unless otherwise marked as required.
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Notes|
+|name|string|The name of the container_request.||
+|description|string|The description of the container_request.||
+|properties|hash|Client-defined structured data that does not affect how the container is run.||
+|state|string|The allowed states are "Uncommitted", "Committed", and "Final".|Once a request is Committed, the only attributes that can be modified are priority, container_uuid, and container_count_max. A request in the "Final" state cannot have any of its functional parts modified (i.e., only name, description, and properties fields can be modified).|
+|requesting_container_uuid|string|The uuid of the parent container that created this container_request, if any. Represents a process tree.|The priority of this container_request is inherited from the parent container, if the parent container is cancelled, this container_request will be cancelled as well.|
+|container_uuid|string|The uuid of the container that satisfies this container_request. The system may return a preexisting Container that matches the container request criteria. See "Container reuse":#container_reuse for more details.|Container reuse is the default behavior, but may be disabled with @use_existing: false@ to always create a new container.|
+|container_count_max|integer|Maximum number of containers to start, i.e., the maximum number of "attempts" to be made.||
+|mounts|hash|Objects to attach to the container's filesystem and stdin/stdout.|See "Mount types":#mount_types for more details.|
+|runtime_constraints|hash|Restrict the container's access to compute resources and the outside world.|Required when in "Committed" state. e.g.,<pre><code>{
+ "ram":12000000000,
+ "vcpus":2,
+ "API":true
+}</code></pre>See "Runtime constraints":#runtime_constraints for more details.|
+|scheduling_parameters|hash|Parameters to be passed to the container scheduler when running this container.|e.g.,<pre><code>{
+"partitions":["fastcpu","vfastcpu"]
+}</code></pre>See "Scheduling parameters":#scheduling_parameters for more details.|
+|container_image|string|Portable data hash of a collection containing the docker image to run the container.|Required.|
+|environment|hash|Environment variables and values that should be set in the container environment (@docker run --env@). This augments and (when conflicts exist) overrides environment variables given in the image's Dockerfile.||
+|cwd|string|Initial working directory, given as an absolute path (in the container) or a path relative to the WORKDIR given in the image's Dockerfile.|Required.|
+|command|array of strings|Command to execute in the container.|Required. e.g., @["echo","hello"]@|
+|output_path|string|Path to a directory or file inside the container that should be preserved as container's output when it finishes. This path must be, or be inside, one of the mount targets. For best performance, point output_path to a writable collection mount.|Required.|
+|priority|integer|Higher value means spend more resources on this container_request, i.e., go ahead of other queued containers, bring up more nodes etc.|Priority 0 means a container should not be run on behalf of this request. Clients are expected to submit container requests with zero priority in order to preview the container that will be used to satisfy it. Priority can be null if and only if state!="Committed".|
+|expires_at|datetime|After this time, priority is considered to be zero.|Not yet implemented.|
+|use_existing|boolean|If possible, use an existing (non-failed) container to satisfy the request instead of creating a new one.|Default is true|
+|log_uuid|string|Log collection containing log messages provided by the scheduler and crunch processes.|Null if the container has not yet completed.|
+|output_uuid|string|Output collection created when the container finished successfully.|Null if the container has failed or not yet completed.|
+|filters|string|Additional constraints for satisfying the container_request, given in the same form as the filters parameter accepted by the container_requests.list API.|
+
+h2(#mount_types). {% include 'mount_types' %}
+
+h2(#runtime_constraints). {% include 'container_runtime_constraints' %}
+
+h2(#scheduling_parameters). {% include 'container_scheduling_parameters' %}
+
+h2(#container_reuse). Container reuse
+
+When a container request is "Committed", the system will try to find and reuse any preexisting Container with the same exact command, cwd, environment, output_path, container_image, mounts, and runtime_constraints as this container request. The serialized fields environment, mounts and runtime_constraints are sorted to facilitate comparison.
+
+The system will use the following scheme to determine which Container to consider for reuse: A Container with the same exact command, cwd, environment, output_path, container_image, mounts, and runtime_constraints as this container request and,
+* The oldest successfully finished container, i.e., in state "Complete" with exit_code of 0. If matching containers with different outputs are found, the system will forgo reusing any of these finished containers and instead look for suitable containers in other states
+* The oldest "Running" container with the highest progress, i.e., the container that is most likely to finish first
+* The oldest "Locked" container with the highest priority, i.e., the container that is most likely to start first
+* The oldest "Queued" container with the highest priority, i.e, the container that is most likely to start first
+
+h2(#cancel_container). Canceling a container request
+
+A container request may be canceled by setting it's priority to 0, using an update call.
+
+When a container request is canceled, it will still reflect the state of the Container it is associated with via the container_uuid attribute. If that Container is being reused by any other container_requests that are still active, i.e., not yet canceled, that Container may continue to run or be scheduled to run by the system in future. However, if no other container_requests are using that Contianer, then the Container will get canceled as well.
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
h2(#create). create
-Create a new ContainerRequest.
+Create a new container request.
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|container_request|object|See "ContainerRequest resource":{{site.baseurl}}/api/schema/ContainerRequest.html|request body||
+{background:#ccffcc}.|container_request|object|Container request resource.|request body||
+
The request body must include the required attributes command, container_image, cwd, and output_path. It can also inlcude other attributes such as environment, mounts, and runtime_constraints.
-h2. delete
+h3. delete
-Delete an existing ContainerRequest.
+Delete an existing container request.
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|uuid|string|The UUID of the ContainerRequest in question.|path||
+{background:#ccffcc}.|uuid|string|The UUID of the container request in question.|path||
-h2. get
+h3. get
-Get a ContainerRequest's metadata by UUID.
+Get a container request's metadata by UUID.
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|uuid|string|The UUID of the ContainerRequest in question.|path||
+{background:#ccffcc}.|uuid|string|The UUID of the container request in question.|path||
-h2. list
+h3. list
List container_requests.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of container_requests to return.|query||
-|order|string|Order in which to return matching container_requests.|query||
-|filters|array|Conditions for filtering container_requests.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-See the create method documentation for more information about ContainerRequest-specific filters.
+See the create method documentation for more information about container request-specific filters.
-h2. update
+h3. update
-Update attributes of an existing ContainerRequest.
+Update attributes of an existing container request.
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|uuid|string|The UUID of the ContainerRequest in question.|path||
+{background:#ccffcc}.|uuid|string|The UUID of the container request in question.|path||
|container_request|object||query||
{% include 'notebox_begin' %}
Setting the priority of a committed container_request to 0 may cancel a running container assigned for it.
-See "Canceling a ContainerRequest":{{site.baseurl}}/api/schema/ContainerRequest.html#cancel_container for further details.
+See "Canceling a container request":{{site.baseurl}}/api/methods/container_requests.html#cancel_container for further details.
{% include 'notebox_end' %}
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/containers@
+Object type: @dz642@
+
+Example UUID: @zzzzz-dz642-0123456789abcde@
+
+h2. Resource
+
+A container is work order to be dispatched to an Arvados cluster to perform some computational work. A container is created in response to a container request. See "computing with Crunch":{{site.baseurl}}/api/execution.html for details.
+
+Each Container offers the following attributes, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Notes|
+|state|string|The allowed states are "Queued", "Locked", "Running", "Cancelled" and "Complete".|See "Container states":#container_states for more details.|
+|started_at|datetime|When this container started running.|Null if container has not yet started.|
+|finished_at|datetime|When this container finished.|Null if container has not yet finished.|
+|log|string|Portable data hash of the collection containing logs from a completed container run.|Null if the container is not yet finished.|
+|environment|hash|Environment variables and values that should be set in the container environment (@docker run --env@). This augments and (when conflicts exist) overrides environment variables given in the image's Dockerfile.|Must be equal to a ContainerRequest's environment in order to satisfy the ContainerRequest.|
+|cwd|string|Initial working directory.|Must be equal to a ContainerRequest's cwd in order to satisfy the ContainerRequest|
+|command|array of strings|Command to execute.| Must be equal to a ContainerRequest's command in order to satisfy the ContainerRequest.|
+|output_path|string|Path to a directory or file inside the container that should be preserved as this container's output when it finishes.|Must be equal to a ContainerRequest's output_path in order to satisfy the ContainerRequest.|
+|mounts|hash|Must contain the same keys as the ContainerRequest being satisfied. Each value must be within the range of values described in the ContainerRequest at the time the Container is assigned to the ContainerRequest.|See "Mount types":#mount_types for more details.|
+|runtime_constraints|hash|Compute resources, and access to the outside world, that are / were available to the container.
+Generally this will contain additional keys that are not present in any corresponding ContainerRequests: for example, even if no ContainerRequests specified constraints on the number of CPU cores, the number of cores actually used will be recorded here.|e.g.,
+<pre><code>{
+ "ram":12000000000,
+ "vcpus":2,
+ "API":true
+}</code></pre>See "Runtime constraints":#runtime_constraints for more details.|
+|scheduling_parameters|hash|Parameters to be passed to the container scheduler when running this container.|e.g.,<pre><code>{
+"partitions":["fastcpu","vfastcpu"]
+}</code></pre>See "Scheduling parameters":#scheduling_parameters for more details.|
+|output|string|Portable data hash of the output collection.|Null if the container is not yet finished.|
+|container_image|string|Portable data hash of a collection containing the docker image used to run the container.||
+|progress|number|A number between 0.0 and 1.0 describing the fraction of work done.||
+|priority|integer|Priority assigned by the system, taking into account the priorities of all associated ContainerRequests.||
+|exit_code|integer|Process exit code.|Null if state!="Complete"|
+|auth_uuid|string|UUID of a token to be passed into the container itself, used to access Keep-backed mounts, etc.|Null if state∉{"Locked","Running"}|
+|locked_by_uuid|string|UUID of a token, indicating which dispatch process changed state to Locked. If null, any token can be used to lock. If not null, only the indicated token can modify this container.|Null if state∉{"Locked","Running"}|
+
+h2(#container_states). Container states
+
+table(table table-bordered table-condensed).
+|_. State|_. Sgnificance|_. Allowed next|
+|Queued|Waiting for a dispatcher to lock it and try to run the container.|Locked, Cancelled|
+|Locked|A dispatcher has "taken" the container and is allocating resources for it. The container has not started yet.|Queued, Running, Cancelled|
+|Running|Resources have been allocated and the contained process has been started (or is about to start). Crunch-run _must_ set state to Running _before_ there is any possibility that user code will run in the container.|Complete, Cancelled|
+|Complete|Container was running, and the contained process/command has exited.|-|
+|Cancelled|The container did not run long enough to produce an exit code. This includes cases where the container didn't even start, cases where the container was interrupted/killed before it exited by itself (e.g., priority changed to 0), and cases where some problem prevented the system from capturing the contained process's exit status (exit code and output).|-|
+
+h2(#mount_types). {% include 'mount_types' %}
+
+h2(#runtime_constraints). {% include 'container_runtime_constraints' %}
+
+h2(#scheduling_parameters). {% include 'container_scheduling_parameters' %}
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
h2(#create). create
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|container|object|See "Container resource":{{site.baseurl}}/api/schema/Container.html|request body||
+{background:#ccffcc}.|container|object|Container resource|request body||
-h2. delete
+h3. delete
Delete an existing Container.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Container in question.|path||
-h2. get
+h3. get
Get a Container's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Container in question.|path||
-h2. list
+h3. list
List containers.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of containers to return.|query||
-|order|string|Order in which to return matching containers.|query||
-|filters|array|Conditions for filtering containers.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
See the create method documentation for more information about Container-specific filters.
-h2. update
+h3. update
Update attributes of an existing Container.
{background:#ccffcc}.|uuid|string|The UUID of the Container in question.|path||
|container|object||query||
-h2. auth
+h3. auth
Get the api_client_authorization record indicated by this container's auth_uuid, which belongs to the container's locked_by_uuid.
navsection: api
navmenu: API Methods
title: "groups"
-
...
+API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/groups@
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
+Object type: @j7d0g@
-API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/groups@
+Example UUID: @zzzzz-j7d0g-0123456789abcde@
-Required arguments are displayed in %{background:#ccffcc}green%.
+h2. Resource
+
+Groups provides a way to apply the same permissions to a set of Arvados objects. See "permission model":{{site.baseurl}}/api/permission-model.html for details.
+
+Each Group has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|||
+|group_class|string|Type of group. This does not affect behavior, but determines how the group is presented in the user interface. For example, @project@ indicates that the group should be displayed by Workbench and arv-mount as a project for organizing and naming objects.|@"project"@
+null|
+|description|text|||
+|writable_by|array|List of UUID strings identifying Users and other Groups that have write permission for this Group. Only users who are allowed to administer the Group will receive a full list. Other users will receive a partial list that includes the Group's owner_uuid and (if applicable) their own user UUID.||
+h2. Methods
-h2. contents
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. contents
Retrieve a list of items owned by the group.
Note: Use filters with the attribute format @<item type>.<field name>@ to filter items of a specific type. For example: @["pipeline_instances.state", "=", "Complete"]@ to filter @pipeline_instances@ where @state@ is @Complete@. All other types of items owned by this group will be unimpacted by this filter and will still be included.
-h2. create
+h3. create
Create a new Group.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|group|object||query||
-h2. delete
+h3. delete
Delete an existing Group.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Group in question.|path||
-h2. get
+h3. get
Gets a Group's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Group in question.|path||
-h2. list
+h3. list
List groups.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of groups to return.|query||
-|order|string|Order in which to return matching groups.|query||
-|filters|array|Conditions for filtering groups.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. show
+h3. show
show groups
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string||path||
-h2. update
+h3. update
Update attributes of an existing Group.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/humans@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @7a9it@
+
+Example UUID: @zzzzz-7a9it-0123456789abcde@
+
+h2. Resource
+
+A metadata record that may be used to represent a human subject.
+
+Each Human has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|properties|hash|||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new Human.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|human|object||query||
-h2. delete
+h3. delete
Delete an existing Human.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Human in question.|path||
-h2. get
+h3. get
Gets a Human's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Human in question.|path||
-h2. list
+h3. list
List humans.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of humans to return.|query||
-|order|string|Order in which to return matching humans.|query||
-|filters|array|Conditions for filtering humans.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Human.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/job_tasks@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @ot0gb@
+
+Example UUID: @zzzzz-ot0gb-0123456789abcde@
+
+h2. Resource
+
+Deprecated.
+A job task is a individually scheduled unit of work executed as part of an overall job.
-h2. create
+Each JobTask has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|sequence|integer|Execution sequence.
+A step cannot be run until all steps with lower sequence numbers have completed.
+Job steps with the same sequence number can be run in any order.||
+|parameters|hash|||
+|output|text|||
+|progress|float|||
+|success|boolean|Is null if the task has neither completed successfully nor failed permanently.||
+
+The following attributes should not be updated by anyone other than the job manager:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Notes|
+|qsequence|integer|Order of arrival|0-based|
+|job_uuid|string|||
+|created_by_job_task_uuid|string|||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new JobTask.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|job_task|object||query||
-h2. delete
+h3. delete
Delete an existing JobTask.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the JobTask in question.|path||
-h2. get
+h3. get
Gets a JobTask's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the JobTask in question.|path||
-h2. list
+h3. list
List job_tasks.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of job_tasks to return.|query||
-|order|string|Order in which to return matching job_tasks.|query||
-|filters|array|Conditions for filtering job_tasks.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing JobTask.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/jobs@
+Object type: @8i9sb@
+
+Example UUID: @zzzzz-8i9sb-0123456789abcde@
+
+h2. Resource
+
+Deprecated.
+
+A job describes a work order to be executed by the Arvados cluster.
+
+Each job has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Notes|
+|script|string|The filename of the job script.|This program will be invoked by Crunch for each job task. It is given as a path to an executable file, relative to the @/crunch_scripts@ directory in the Git tree specified by the _repository_ and _script_version_ attributes.|
+|script_parameters|hash|The input parameters for the job.|Conventionally, one of the parameters is called @"input"@. Typically, some parameter values are collection UUIDs. Ultimately, though, the significance of parameters is left entirely up to the script itself.|
+|repository|string|Git repository name or URL.|Source of the repository where the given script_version is to be found. This can be given as the name of a locally hosted repository, or as a publicly accessible URL starting with @git://@, @http://@, or @https://@.
+Examples:
+@yourusername/yourrepo@
+@https://github.com/curoverse/arvados.git@|
+|script_version|string|Git commit|During a **create** transaction, this is the Git branch, tag, or hash supplied by the client. Before the job starts, Arvados updates it to the full 40-character SHA-1 hash of the commit used by the job.
+See "Specifying Git versions":#script_version below for more detail about acceptable ways to specify a commit.|
+|cancelled_by_client_uuid|string|API client ID|Is null if job has not been cancelled|
+|cancelled_by_user_uuid|string|Authenticated user ID|Is null if job has not been cancelled|
+|cancelled_at|datetime|When job was cancelled|Is null if job has not been cancelled|
+|started_at|datetime|When job started running|Is null if job has not [yet] started|
+|finished_at|datetime|When job finished running|Is null if job has not [yet] finished|
+|running|boolean|Whether the job is running||
+|success|boolean|Whether the job indicated successful completion|Is null if job has not finished|
+|is_locked_by_uuid|string|UUID of the user who has locked this job|Is null if job is not locked. The system user locks the job when starting the job, in order to prevent job attributes from being altered.|
+|node_uuids|array|List of UUID strings for node objects that have been assigned to this job||
+|log|string|Collection UUID|Is null if the job has not finished. After the job runs, the given collection contains a text file with log messages provided by the @arv-crunch-job@ task scheduler as well as the standard error streams provided by the task processes.|
+|tasks_summary|hash|Summary of task completion states.|Example: @{"done":0,"running":4,"todo":2,"failed":0}@|
+|output|string|Collection UUID|Is null if the job has not finished.|
+|nondeterministic|boolean|The job is expected to produce different results if run more than once.|If true, this job will not be considered as a candidate for automatic re-use when submitting subsequent identical jobs.|
+|submit_id|string|Unique ID provided by client when job was submitted|Optional. This can be used by a client to make the "jobs.create":{{site.baseurl}}/api/methods/jobs.html#create method idempotent.|
+|priority|string|||
+|arvados_sdk_version|string|Git commit hash that specifies the SDK version to use from the Arvados repository|This is set by searching the Arvados repository for a match for the arvados_sdk_version runtime constraint.|
+|docker_image_locator|string|Portable data hash of the collection that contains the Docker image to use|This is set by searching readable collections for a match for the docker_image runtime constraint.|
+|runtime_constraints|hash|Constraints that must be satisfied by the job/task scheduler in order to run the job.|See below.|
+|components|hash|Name and uuid pairs representing the child work units of this job. The uuids can be of different object types.|Example components hash: @{"name1": "zzzzz-8i9sb-xyz...", "name2": "zzzzz-d1hrv-xyz...",}@|
+
+h3(#script_version). Specifying Git versions
+
+The script_version attribute and arvados_sdk_version runtime constraint are typically given as a branch, tag, or commit hash, but there are many more ways to specify a Git commit. The "specifying revisions" section of the "gitrevisions manual page":http://git-scm.com/docs/gitrevisions.html has a definitive list. Arvados accepts Git versions in any format listed there that names a single commit (not a tree, a blob, or a range of commits). However, some kinds of names can be expected to resolve differently in Arvados than they do in your local repository. For example, <code>HEAD@{1}</code> refers to the local reflog, and @origin/master@ typically refers to a remote branch: neither is likely to work as desired if given as a Git version.
+
+h3. Runtime constraints
+
+table(table table-bordered table-condensed).
+|_. Key|_. Type|_. Description|_. Implemented|
+|arvados_sdk_version|string|The Git version of the SDKs to use from the Arvados git repository. See "Specifying Git versions":#script_version for more detail about acceptable ways to specify a commit. If you use this, you must also specify a @docker_image@ constraint (see below). In order to install the Python SDK successfully, Crunch must be able to find and run virtualenv inside the container.|✓|
+|docker_image|string|The Docker image that this Job needs to run. If specified, Crunch will create a Docker container from this image, and run the Job's script inside that. The Keep mount and work directories will be available as volumes inside this container. The image must be uploaded to Arvados using @arv keep docker@. You may specify the image in any format that Docker accepts, such as @arvados/jobs@, @debian:latest@, or the Docker image id. Alternatively, you may specify the portable data hash of the image Collection.|✓|
+|min_nodes|integer||✓|
+|max_nodes|integer|||
+|min_cores_per_node|integer|Require that each node assigned to this Job have the specified number of CPU cores|✓|
+|min_ram_mb_per_node|integer|Require that each node assigned to this Job have the specified amount of real memory (in MiB)|✓|
+|min_scratch_mb_per_node|integer|Require that each node assigned to this Job have the specified amount of scratch storage available (in MiB)|✓|
+|max_tasks_per_node|integer|Maximum simultaneous tasks on a single node|✓|
+|keep_cache_mb_per_task|integer|Size of file data buffer for per-task Keep directory ($TASK_KEEPMOUNT), in MiB. Default is 256 MiB. Increase this to reduce cache thrashing in situtations such as accessing multiple large (64+ MiB) files at the same time, or accessing different parts of a large file at the same time.|✓|
+|min_ram_per_task|integer|Minimum real memory (KiB) per task||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
-h2. cancel
+h3. cancel
Cancel a job that is queued or running.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string||path||
-h2(#create). create
+h3(#create). create
Create a new Job.
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|job|object|See "Job resource":{{site.baseurl}}/api/schema/Job.html|request body||
+{background:#ccffcc}.|job|object|Job resource|request body||
|minimum_script_version |string |Git branch, tag, or commit hash specifying the minimum acceptable script version (earliest ancestor) to consider when deciding whether to re-use a past job.[1]|query|@"c3e86c9"@|
|exclude_script_versions|array of strings|Git commit branches, tags, or hashes to exclude when deciding whether to re-use a past job.|query|@["8f03c71","8f03c71"]@
@["badtag1","badtag2"]@|
When a job is submitted to the queue using the **create** method, the @script_version@ attribute is updated to a full 40-character Git commit hash based on the current content of the specified repository. If @script_version@ cannot be resolved, the job submission is rejected.
-fn1. See the "note about specifying Git commits on the Job resource page":{{site.baseurl}}/api/schema/Job.html#script_version for more detail.
+fn1. See the "note about specifying Git commits":#script_version for more detail.
-h3. Specialized filters
+h4. Specialized filters
Special filter operations are available for specific Job columns.
* @docker_image_locator@ @not in docker@ @SEARCH@<br>Negate the @in docker@ filter.
-h3. Reusing jobs
+h4. Reusing jobs
Because Arvados records the exact version of the script, input parameters, and runtime environment that was used to run the job, if the script is deterministic (meaning that the same code version is guaranteed to produce the same outputs from the same inputs) then it is possible to re-use the results of past jobs, and avoid re-running the computation to save time. Arvados uses the following algorithm to determine if a past job can be re-used:
</div>
-h3. Examples
+h4. Examples
Run the script "crunch_scripts/hash.py" in the repository "you" using the "master" commit. Arvados should re-use a previous job if the script_version of the previous job is the same as the current "master" commit. This works irrespective of whether the previous job was submitted using the name "master", a different branch name or tag indicating the same commit, a SHA-1 commit hash, etc.
}
</pre></notextile>
-h2. delete
+h3. delete
Delete an existing Job.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Job in question.|path||
-h2. get
+h3. get
Gets a Job's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Job in question.|path||
-h2. list
+h3. list
List jobs.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of jobs to return.|query||
-|order|string|Order in which to return matching jobs.|query||
-|filters|array|Conditions for filtering jobs.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
See the create method documentation for more information about Job-specific filters.
-h2. log_tail_follow
+h3. log_tail_follow
log_tail_follow jobs
{background:#ccffcc}.|uuid|string||path||
|buffer_size|integer (default 8192)||query||
-h2. queue
+h3. queue
Get the current job queue.
This method is equivalent to the "list method":#list, except that the results are restricted to queued jobs (i.e., jobs that have not yet been started or cancelled) and order defaults to queue priority.
-h2. update
+h3. update
Update attributes of an existing Job.
layout: default
navsection: api
navmenu: API Methods
-title: "keep_disks"
+title: "keep_disks (deprecated)"
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/keep_disks@
+Object type: @penuu@
+
+Example UUID: @zzzzz-penuu-0123456789abcde@
+
+h2. Resource
+
+Obsoleted by "keep_services":{{site.baseurl}}/api/methods/keep_services.html
+
+Each KeepDisk has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|ping_secret|string|||
+|node_uuid|string|||
+|filesystem_uuid|string|||
+|bytes_total|integer|||
+|bytes_free|integer|||
+|is_readable|boolean|||
+|is_writable|boolean|||
+|last_read_at|datetime|||
+|last_write_at|datetime|||
+|last_ping_at|datetime|||
+|keep_service_uuid|string|||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new KeepDisk.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|keep_disk|object||query||
-h2. delete
+h3. delete
Delete an existing KeepDisk.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the KeepDisk in question.|path||
-h2. get
+h3. get
Gets a KeepDisk's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the KeepDisk in question.|path||
-h2. list
+h3. list
List keep_disks.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of keep_disks to return.|query||
-|order|string|Order in which to return matching keep_disks.|query||
-|filters|array|Conditions for filtering keep_disks.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. ping
+h3. ping
ping keep_disks
|service_host|string||query||
|uuid|string||query||
-h2. update
+h3. update
Update attributes of an existing KeepDisk.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/keep_services@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @bi6l4@
+
+Example UUID: @zzzzz-bi6l4-0123456789abcde@
+
+h2. Resource
+
+The keep_services resource keep clients to discover storage servers and proxies available on the cluster for persistent storage and retrieval of keep blocks.
+
+Each KeepService has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|service_host|string|hostname of the server||
+|service_port|integer|TCP port of the service||
+|service_ssl_flag|boolean|if the server uses SSL||
+|service_type|string|The service type, one of "disk", "blob" (cloud object store) or "proxy" (keepproxy)||
-h2. accessible
+h2. Methods
-Get a list of keep services that are accessible to the requesting client. This
-is context-sensitive, for example providing the list of actual Keep servers
-when inside the cluster, but providing a proxy service if client contacts
-Arvados from outside the cluster.
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
-Takes no arguments.
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. accessible
-h2. create
+Get a list of keep services that are accessible to the requesting client. Unlike @list@, this is context-sensitive based on the requester, for example providing the list of actual Keep servers when inside the cluster, but providing a proxy service if client contacts Arvados from outside the cluster.
+
+h3. create
Create a new KeepService.
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|keep_disk|object||query||
+|keep_service|object||query||
-h2. delete
+h3. delete
Delete an existing KeepService.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the KeepService in question.|path||
-h2. get
+h3. get
Gets a KeepService's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the KeepService in question.|path||
-h2. list
+h3. list
List keep_services.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of keep_services to return.|query||
-|order|string|Order in which to return matching keep_services.|query||
-|filters|array|Conditions for filtering keep_services.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing KeepService.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/links@
+Object type: @o0j2j@
+
+Example UUID: @zzzzz-o0j2j-0123456789abcde@
+
+h2. Resource
+
+Links are an extensible way to describe relationships between Arvados objects and metadata about individual objects.
+
+Each link has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|
+|head_uuid|string|The object being described or acted on.|
+|tail_uuid|string|The origin or actor in the description or action (may be null).|
+|link_class|string|Type of link|
+|name|string|Primary value of the link.|
+|properties|hash|Additional information, expressed as a key→value hash. Key: string. Value: string, number, array, or hash.|
+
+h2. Link classes
+
+Some classes are pre-defined by convention and have standard meanings attached to names.
+
+h3. permission
+
+See "permission links":{{site.baseurl}}/api/permission-model.html#links section of the permission model.
+
+h3. tag
+
+A **tag** link describes an object using an unparsed plain text string. Tags can be used to annotate objects that are not editable, like collections and objects shared as read-only.
+
+table(table table-bordered table-condensed).
+|_. tail_type→head_type|_. name→head_uuid {properties}|
+|→Collection | _tag name_ → _collection uuid_|
+|→Job | _tag name_ → _job uuid_|
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new Link.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|link|object||query||
-h2. delete
+h3. delete
Delete an existing Link.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Link in question.|path||
-h2. get
+h3. get
Gets a Link's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Link in question.|path||
-h2. list
+h3. list
List links.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of links to return.|query||
-|order|string|Order in which to return matching links.|query||
-|filters|array|Conditions for filtering links.|query||
-
-h2. render_not_found
-
-render_not_found links
-
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|a|string||path||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Link.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/logs@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @57u5n@
+
+Example UUID: @zzzzz-57u5n-0123456789abcde@
+
+h2. Resource
+
+Each Log has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|object_uuid|string|The arvados object that is the subject of the log.||
+|event_at|datetime|||
+|event_type|string|A user-defined category or type for this event.|@LOGIN@|
+|summary|text|||
+|properties|hash|||
+
+h3. Creation
+
+Any user may create Log entries for any event they find useful. User-generated Logs have no intrinsic meaning to other users or to the Arvados system itself; it is up to each user to choose appropriate log event types and summaries for their project.
+h3. System Logs
-h2. create
+Arvados uses Logs to record creation, deletion, and updates of other Arvados resources.
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new log entry.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|log|object||query||
-h2. delete
+h3. delete
Delete an existing log entry. This method can only be used by privileged (system administrator) users.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the log entry in question.|path||
-h2. get
+h3. get
Retrieve a log entry.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the log entry in question.|path||
-h2. list
+h3. list
List log entries.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of log entries to return.|query||
-|order|string|Order in which to return matching log entries.|query||
-|filters|array|Conditions for filtering log entries.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing log entry. This method can only be used by privileged (system administrator) users.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/nodes@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @7ekkf@
+
+Example UUID: @zzzzz-7ekkf-0123456789abcde@
+
+h2. Resource
+
+Node resources list compute nodes on which Crunch may schedule work.
+
+Each Node has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|slot_number|integer|||
+|hostname|string|||
+|domain|string|||
+|ip_address|string|||
+|job_uuid|string|The UUID of the job that this node is assigned to work on. If you do not have permission to read the job, this will be null.||
+|first_ping_at|datetime|||
+|last_ping_at|datetime|||
+|info|hash|||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new Node.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|node|object||query||
-h2. delete
+h3. delete
Delete an existing Node.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Node in question.|path||
-h2. get
+h3. get
Gets a Node's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Node in question.|path||
-h2. list
+h3. list
List nodes.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of nodes to return.|query||
-|order|string|Order in which to return matching nodes.|query||
-|filters|array|Conditions for filtering nodes.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. ping
+h3. ping
-ping nodes
+Process a ping from a compute node.
Arguments:
{background:#ccffcc}.|ping_secret|string||query||
{background:#ccffcc}.|uuid|string||path||
-h2. update
+h3. update
Update attributes of an existing Node.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/pipeline_instances@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @d1hrv@
+
+Example UUID: @zzzzz-d1hrv-0123456789abcde@
+
+h2. Resource
+
+Deprecated. A pipeline instance is a collection of jobs managed by @aravdos-run-pipeline-instance@.
+
+Each PipelineInstance has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|pipeline_template_uuid|string|The "pipeline template":pipeline_templates.html that this instance was created from.||
+|name|string|||
+|components|hash|||
+|success|boolean|||
+|active|boolean|||
+|properties|Hash|||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new PipelineInstance.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|pipeline_instance|object||query||
-h2. delete
+h3. delete
Delete an existing PipelineInstance.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the PipelineInstance in question.|path||
-h2. get
+h3. get
Gets a PipelineInstance's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the PipelineInstance in question.|path||
-h2. list
+h3. list
List pipeline_instances.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of pipeline_instances to return.|query||
-|order|string|Order in which to return matching pipeline_instances.|query||
-|filters|array|Conditions for filtering pipeline_instances.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing PipelineInstance.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/pipeline_templates@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @p5p6p@
+
+Example UUID: @zzzzz-p5p6p-0123456789abcde@
+
+h2. Resource
+
+Deprecated. A pipeline template is a collection of jobs that can be instantiated as a pipeline_instance.
+
+Each PipelineTemplate has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|||
+|components|hash|||
+
+The pipeline template consists of "name" and "components".
+
+table(table table-bordered table-condensed).
+|_. Attribute |_. Type |_. Accepted values |_. Required|_. Description|
+|name |string |any |yes |The human-readable name of the pipeline template.|
+|components |object |JSON object containing job submission objects|yes |The component jobs that make up the pipeline, with the component name as the key. |
+
+h3. Components
+The components field of the pipeline template is a JSON object which describes the individual steps that make up the pipeline. Each component is an Arvados job submission. "Parameters for job submissions are described on the job method page.":{{site.baseurl}}/api/methods/jobs.html#create In addition, a component can have the following parameters:
-h2. create
+table(table table-bordered table-condensed).
+|_. Attribute |_. Type |_. Accepted values |_. Required|_. Description|
+|output_name |string or boolean|string or false |no |If a string is provided, use this name for the output collection of this component. If the value is false, do not create a permanent output collection (an temporary intermediate collection will still be created). If not provided, a default name will be assigned to the output.|
+
+h3. Script parameters
+
+When used in a pipeline, each parameter in the 'script_parameters' attribute of a component job can specify that the input parameter must be supplied by the user, or the input parameter should be linked to the output of another component. To do this, the value of the parameter should be JSON object containing one of the following attributes:
+
+table(table table-bordered table-condensed).
+|_. Attribute |_. Type |_. Accepted values |_. Description|
+|default |any |any |The default value for this parameter.|
+|required |boolean |true or false |Specifies whether the parameter is required to have a value or not.|
+|dataclass |string |One of 'Collection', 'File' [1], 'number', or 'text' |Data type of this parameter.|
+|search_for |string |any string |Substring to use as a default search string when choosing inputs.|
+|output_of |string |the name of another component in the pipeline |Specifies that the value of this parameter should be set to the 'output' attribute of the job that corresponds to the specified component.|
+|title |string |any string |User friendly title to display when choosing parameter values|
+|description |string |any string |Extended text description for describing expected/valid values for the script parameter|
+|link_name |string |any string |User friendly name to display for the parameter value instead of the actual parameter value|
+
+The 'output_of' parameter is especially important, as this is how components are actually linked together to form a pipeline. Component jobs that depend on the output of other components do not run until the parent job completes and has produced output. If the parent job fails, the entire pipeline fails.
+
+fn1. The 'File' type refers to a specific file within a Keep collection in the form 'collection_hash/filename', for example '887cd41e9c613463eab2f0d885c6dd96+83/bob.txt'.
+
+The 'search_for' parameter is meaningful only when input dataclass of type Collection or File is used. If a value is provided, this will be preloaded into the input data chooser dialog in Workbench. For example, if your input dataclass is a File and you are interested in a certain filename extention, you can preconfigure it in this attribute.
+
+h3. Examples
+
+This is a pipeline named "Filter MD5 hash values" with two components, "do_hash" and "filter". The "input" script parameter of the "do_hash" component is required to be filled in by the user, and the expected data type is "Collection". This also specifies that the "input" script parameter of the "filter" component is the output of "do_hash", so "filter" will not run until "do_hash" completes successfully. When the pipeline runs, past jobs that meet the criteria described above may be substituted for either or both components to avoid redundant computation.
+
+<notextile><pre>
+{
+ "name": "Filter MD5 hash values",
+ "components": {
+ "do_hash": {
+ "script": "hash.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": {
+ "input": {
+ "required": true,
+ "dataclass": "Collection",
+ "search_for": ".fastq.gz",
+ "title":"Please select a fastq file"
+ }
+ },
+ },
+ "filter": {
+ "script": "0-filter.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": {
+ "input": {
+ "output_of": "do_hash"
+ }
+ },
+ }
+ }
+}
+</pre></notextile>
+
+This pipeline consists of three components. The components "thing1" and "thing2" both depend on "cat_in_the_hat". Once the "cat_in_the_hat" job is complete, both "thing1" and "thing2" can run in parallel, because they do not depend on each other.
+
+<notextile><pre>
+{
+ "name": "Wreck the house",
+ "components": {
+ "cat_in_the_hat": {
+ "script": "cat.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": { }
+ },
+ "thing1": {
+ "script": "thing1.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": {
+ "input": {
+ "output_of": "cat_in_the_hat"
+ }
+ },
+ },
+ "thing2": {
+ "script": "thing2.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": {
+ "input": {
+ "output_of": "cat_in_the_hat"
+ }
+ },
+ },
+ }
+}
+</pre></notextile>
+
+This pipeline consists of three components. The component "cleanup" depends on "thing1" and "thing2". Both "thing1" and "thing2" are started immediately and can run in parallel, because they do not depend on each other, but "cleanup" cannot begin until both "thing1" and "thing2" have completed.
+
+<notextile><pre>
+{
+ "name": "Clean the house",
+ "components": {
+ "thing1": {
+ "script": "thing1.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": { }
+ },
+ "thing2": {
+ "script": "thing2.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": { }
+ },
+ "cleanup": {
+ "script": "cleanup.py",
+ "repository": "<b>you</b>/<b>you</b>",
+ "script_version": "master",
+ "script_parameters": {
+ "mess1": {
+ "output_of": "thing1"
+ },
+ "mess2": {
+ "output_of": "thing2"
+ }
+ }
+ }
+ }
+}
+</pre></notextile>
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new PipelineTemplate.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|pipeline_template|object||query||
-h2. delete
+h3. delete
Delete an existing PipelineTemplate.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the PipelineTemplate in question.|path||
-h2. get
+h3. get
Gets a PipelineTemplate's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the PipelineTemplate in question.|path||
-h2. list
+h3. list
List pipeline_templates.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of pipeline_templates to return.|query||
-|order|string|Order in which to return matching pipeline_templates.|query||
-|filters|array|Conditions for filtering pipeline_templates.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing PipelineTemplate.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/repositories@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @s0uqq@
+
+Example UUID: @zzzzz-s0uqq-0123456789abcde@
+
+h2. Resource
+
+The repositories resource lists git repositories managed by Arvados.
+
+Each Repository has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|The name of the repository on disk. Repository names must begin with a letter and contain only alphanumerics. Unless the repository is owned by the system user, the name must begin with the owner's username, then be separated from the base repository name with @/@. You may not create a repository that is owned by a user without a username.|@username/project1@|
+|clone_urls|array|URLs from which the repository can be cloned. Read-only.|@["git@git.zzzzz.arvadosapi.com:foo/bar.git",
+ "https://git.zzzzz.arvadosapi.com/foo/bar.git"]@|
+|fetch_url|string|URL suggested as a fetch-url in git config. Deprecated. Read-only.||
+|push_url|string|URL suggested as a push-url in git config. Deprecated. Read-only.||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new Repository.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|repository|object||query||
-h2. delete
+h3. delete
Delete an existing Repository.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Repository in question.|path||
-h2. get
+h3. get
Gets a Repository's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Repository in question.|path||
-h2. get_all_permissions
+h3. get_all_permissions
get_all_permissions repositories
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-h2. list
+h3. list
List repositories.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of repositories to return.|query||
-|order|string|Order in which to return matching repositories.|query||
-|filters|array|Conditions for filtering repositories.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Repository.
navsection: api
navmenu: API Methods
title: "specimens"
-
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/specimens@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @j58dm@
+
+Example UUID: @zzzzz-j58dm-0123456789abcde@
+
+h2. Resource
+
+A metadata record that may be used to represent a biological specimen.
+
+Each Specimen has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|material|string|||
+|properties|hash|||
+
+h2. Methods
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new Specimen.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|specimen|object||query||
-h2. delete
+h3. delete
Delete an existing Specimen.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Specimen in question.|path||
-h2. get
+h3. get
Gets a Specimen's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Specimen in question.|path||
-h2. list
+h3. list
List specimens.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of specimens to return.|query||
-|order|string|Order in which to return matching specimens.|query||
-|filters|array|Conditions for filtering specimens.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Specimen.
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/traits@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @q1cn2@
+
+Example UUID: @zzzzz-q1cn2-0123456789abcde@
+
+h2. Resource
+
+A metadata record that may be used to represent a genotype or phenotype trait.
+
+Each Trait has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|||
+|properties|hash|||
+h2. Methods
-h2. create
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new Trait.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|trait|object||query||
-h2. delete
+h3. delete
Delete an existing Trait.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Trait in question.|path||
-h2. get
+h3. get
Gets a Trait's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Trait in question.|path||
-h2. list
+h3. list
List traits.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of traits to return.|query||
-|order|string|Order in which to return matching traits.|query||
-|filters|array|Conditions for filtering traits.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Trait.
navsection: api
navmenu: API Methods
title: "users"
-
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/users@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @tpzed@
+Example UUID: @zzzzz-tpzed-0123456789abcde@
-h2. create
+h2. Resource
+
+Users represent individuals with access to the Arvados cluster.
+
+Each User has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|email|string|||
+|username|string|The username used for the user's git repositories and virtual machine logins. Usernames must start with a letter, and contain only alphanumerics. When a new user is created, a default username is set from their e-mail address. Only administrators may change the username.||
+|first_name|string|||
+|last_name|string|||
+|identity_url|string|||
+|is_admin|boolean|||
+|prefs|hash|||
+|default_owner_uuid|string|||
+|is_active|boolean|||
+|writable_by|array|List of UUID strings identifying Groups and other Users that can modify this User object. This will include the user's owner_uuid and, for administrators and users requesting their own User object, the requesting user's UUID.||
+
+h2. Methods
+
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
+
+h3. create
Create a new User.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|user|object||query||
-h2. current
+h3. current
-current users
+Get the user associated with the provided API token.
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-h2. delete
+h3. delete
Delete an existing User.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string||path||
-h2. get
+h3. get
Gets a User's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the User in question.|path||
-h2. list
+h3. list
List users.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of users to return.|query||
-|order|string|Order in which to return matching users.|query||
-|filters|array|Conditions for filtering users.|query||
-
-h2. show
-
-show users
-
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|uuid|string||path||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. system
+h3. system
-system users
+Get the user record for the "system user.":{{site.baseurl}}/api/permission-model.html#system
Arguments:
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-h2. update
+h3. update
Update attributes of an existing User.
navsection: api
navmenu: API Methods
title: "virtual_machines"
-
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/virtual_machines@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @2x53u@
+
+Example UUID: @zzzzz-2x53u-0123456789abcde@
+
+h2. Resource
+
+The virtual_machines resource lists compute resources in the Arvados cluster to which a user may log in to get an interactive shell (via ssh or webshell).
+
+Each VirtualMachine has, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|hostname|string|||
+
+h2. Methods
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new VirtualMachine.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
|virtual_machine|object||query||
-h2. delete
+h3. delete
Delete an existing VirtualMachine.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the VirtualMachine in question.|path||
-h2. get
+h3. get
Gets a VirtualMachine's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the VirtualMachine in question.|path||
-h2(#logins). logins
+h3(#logins). logins
Get a list of SSH keys and account names that should be able to log in to a given virtual machine.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string||path||
-The response is a "resource list":{{site.baseurl}}/api/resources.html#resourceList with @kind@ set to @"arvados#HashList"@. Each item is a hash with the following keys:
+The response is an object with the field @items@ containing an array of objects in the following format:
table(table table-bordered table-condensed).
|_. Key|_. Value type|_. Description|_. Example|
|hostname|string|Hostname of the virtual machine|@"shell.xyzzy.arvadosapi.com"@|
|public_key|string|SSH public key|@"ssh-rsa AAAAB3NzaC1yc2E..."@|
|user_uuid|string|UUID of the user who should be able to log in|@"xyzzy-tpzed-mv4d7dy7n91te11"@|
-|virtual_machine_uuid|string|UUID of the "VirtualMachine resource":{{site.baseurl}}/api/schema/VirtualMachine.html|@"xyzzy-2x53u-kvszmclnbjuv8xc"@|
-|authorized_key_uuid|string|UUID of the "AuthorizedKey resource":{{site.baseurl}}/api/schema/AuthorizedKey.html|@"xyzzy-fngyi-v9p0cyfmjxbio64"@|
+|virtual_machine_uuid|string|UUID of the "virtual machine resource":{{site.baseurl}}/api/methods/virtual_machines.html|@"zzzzz-2x53u-kvszmclnbjuv8xc"@|
+|authorized_key_uuid|string|UUID of the "authorized key resource":{{site.baseurl}}/api/methods/authorized_keys.html|@"zzzzz-fngyi-v9p0cyfmjxbio64"@|
-h2. get_all_logins
+h3. get_all_logins
-Get a list, for every virtual machine in the system, of SSH keys and account names that should be able to log in.
+Get a list of SSH keys and account names that should be able to log in for every virtual machine in the system.
Arguments: none.
The response has the same format as the response to the "logins method":#logins above.
-h2. list
+h3. list
List virtual_machines.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of virtual_machines to return.|query||
-|order|string|Order in which to return matching virtual_machines.|query||
-|filters|array|Conditions for filtering virtual_machines.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing VirtualMachine.
navsection: api
navmenu: API Methods
title: "workflows"
-
...
-See "REST methods for working with Arvados resources":{{site.baseurl}}/api/methods.html
-
API endpoint base: @https://{{ site.arvados_api_host }}/arvados/v1/workflows@
-Required arguments are displayed in %{background:#ccffcc}green%.
+Object type: @7fd4e@
+
+Example UUID: @zzzzz-7fd4e-0123456789abcde@
+
+h2. Resource
+
+Stores a "Common Workflow Language":http://commonwl.org (CWL) computational workflow that can be searched for, browsed and executed (submitted to Crunch) from the workbench.
+
+Each Workflow offers the following optional attributes, in addition to the "Common resource fields":{{site.baseurl}}/api/resources.html:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Example|
+|name|string|If not specified, will be set to any "name" from the "definition" attribute.||
+|description|string|If not specified, will be set to any "description" from the "definition" attribute.||
+|definition|string|A "Common Workflow Language" document.|Visit "Common Workflow Language":http://www.commonwl.org/ for details.|
+
+h2. Methods
+See "Common resource methods":{{site.baseurl}}/api/methods.html for more information about @create@, @delete@, @get@, @list@, and @update@.
+
+Required arguments are displayed in %{background:#ccffcc}green%.
-h2. create
+h3. create
Create a new Workflow.
table(table table-bordered table-condensed).
|_. Argument |_. Type |_. Description |_. Location |_. Example |
-{background:#ccffcc}.|workflow|object|See "Workflow resource":{{site.baseurl}}/api/schema/Workflow.html|request body||
+{background:#ccffcc}.|workflow|object|Workflow resource|request body||
-h2. delete
+h3. delete
Delete an existing Workflow.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Workflow in question.|path||
-h2. get
+h3. get
Get a Workflow's metadata by UUID.
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Workflow in question.|path||
-h2. list
+h3. list
List workflows.
-Arguments:
-
-table(table table-bordered table-condensed).
-|_. Argument |_. Type |_. Description |_. Location |_. Example |
-|limit|integer (default 100)|Maximum number of workflows to return.|query||
-|order|string|Order in which to return matching workflows.|query||
-|filters|array|Conditions for filtering workflows.|query||
+See "common resource list method.":{{site.baseurl}}/api/methods.html#index
-h2. update
+h3. update
Update attributes of an existing Workflow.
navsection: api
navmenu: Concepts
title: "Permission model"
-
...
+* There are four levels of permission: *none*, *can_read*, *can_write*, and *can_manage*.
+** *none* is the default state when there are no other permission grants.
+*** the object is not included in any list query response.
+*** direct queries of the object by uuid return 404 Not Found.
+*** Link objects require valid identifiers in @head_uuid@ and @tail_uuid@, so an attempt to create a Link that references an unreadable object will return an error indicating the object is not found.
+** *can_read* grants read-only access to the record. Attempting to update or delete the record returns an error. *can_read* does not allow a reader to see any permission grants on the object except the object's owner_uuid and the reader's own permissions.
+** *can_write* permits changes to the record (but not permission links). *can_write* permits the user to delete the object. *can_write* also implies *can_read*.
+** *can_manage* permits the user to read, create, update and delete permission links whose @head_uuid@ is this object's @uuid@. *can_manage* also implies *can_write* and *can_read*.
+h2. Ownership
-Each API transaction (read, write, create, etc.) is done on behalf of a person.
-
-* An end user, via a web app
-* The owner of an installed app
-
-A user (person) is permitted to act on an object if there is a path (series of permission Links) from the acting user to the object in which
-
-* Every intervening object is a Group, and
-* Every intervening permission Link allows the current action
-
-Special case: A permission path can also include intervening User objects if the links _to_ the Users are "can_manage" links.
-
-Each object has exactly one _owner_, which can be either a User or a Group.
-
-* If the owner of X is A, then A is permitted to do any action on X.
-
-h3. Tokens
-
-An authorization token is issued at a user's request, and supplied to an API client using some suitable mechanism (_e.g._, cookie or application config file for a web app; environment variable or .rc-file for a CLI app).
-
-A user can have multiple valid tokens at a given time. At the user's option, a token can be restricted to a combination of
-
-* API client program
-* time interval
-* transaction type
-
-h3. System pseudo-user
-
-A privileged user account exists for the use of built-in Arvados system components. This user manages system-wide shared objects which can't really be "owned" by any particular user, like
-
-* Jobs and job steps (because a given job can be "wanted" by multiple users)
-* Provenance metadata (because no user should be able to modify this directly)
-* Storage metadata like
-** redundancy verified as N× at time Y
-** contents of collections A and B are identical
-
-The system pseudo-user's uuid is @{siteprefix}-tpzed-000000000000000@.
-
-h2. Example scenarios
-
-h3. 1. Private objects
-
-Alfred stores 3 data Collections in Keep and adds them to a new Group.
-
-The Collections and the Group can only be seen by Alfred, administrators, and the system user.
-
-The data in the Collections can only be retrieved by Alfred, administrators, and the system user.
-
-h3. 2. Public objects
-
-George creates a "PGP public data" Group, and grants "read" permission to all users.
-
-* ...by adding a Link: "All users" Group _can_read_→ "PGP public data" Group
-
-George stores 4 data Collections in Keep and adds them to the "PGP public data" Group
+* All Arvados objects have an @owner_uuid@ field. Valid uuid types for @owner_uuid@ are "User" and "Group".
+* The User or Group specified by @owner_uuid@ has *can_manage* permission on the object.
+** This permission is one way: A User or Group's @owner_uuid@ being equal to @X@ does not imply any permission for that User/Group to read, write, or manage an object whose @uuid@ is equal to @X@.
+* Applications should represent each object as belonging to, or being "inside", the Group/User referenced by its @owner_uuid@.
+** A "project" is a subtype of Group that is treated as a "Project" in Workbench, and as a directory by @arv-mount@.
+** A "role" is a subtype of Group that is treated in Workbench as a group of users who have permissions in common (typically an organizational group).
+* To change the @owner_uuid@ field, it is necessary to have @can_write@ permission on both the current owner and the new owner.
-* ...by adding a Link: Group _can_read_→ Collection
+h2(#links). Permission links
-Anyone who can connect to Arvados can log in with a Google/OpenID account and read the data.
+A link object with
-h3. 3. Group-managed objects
+* @owner_uuid@ of the system user.
+* @link_class@ "permission"
+* @name@ one of *can_read*, *can_write* or *can_manage*
+* @head_uuid@ of some Arvados object
+* @tail_uuid@ of a User or Group
-Three lab members are working together on a project. All Specimens, Links, Jobs, etc. can be modified by any of the three lab members. _Other_ lab members, who are not working on this project, can view but not modify these objects.
+grants the @name@ permission for @tail_uuid@ accessing @head_uuid@
-h3. 4. Group-level administrator
+* If a User has *can_manage* permission on some object, this grants permission to read, create, update and delete permission links where the @head_uuid@ is the object under management.
-The Ashton Lab administrator, Alison, manages user accounts within her lab. She can enable and disable accounts, and exercise any permission that her lab members have.
+h3. Transitive permissions
-George has read-only access to the same set of accounts. This lets him see things like user activity and resource usage reports, without worrying about accidentally messing up anyone's data.
+Permissions can be obtained indirectly through Groups.
+* If a User X *can_read* Group A, and Group A *can_read* Object B, then User X *can_read* Object B.
+* Permissions are narrowed to the least powerful permission on the path.
+** If User X *can_write* Group A, and Group A *can_read* Object B, then User X *can_read* Object B.
+** If User X *can_read* Group A, and Group A *can_write* Object B, then User X *can_read* Object B.
-table(table table-bordered table-condensed).
-|Tail |Permission |Head |Effect|
-|Group: Ashton Lab Admin|can_manage |User: Lab Member 1 |Lab member 1 is in this administrative group|
-|Group: Ashton Lab Admin|can_manage |User: Lab Member 2 |Lab member 2 is in this administrative group|
-|Group: Ashton Lab Admin|can_manage |User: Lab Member 3 |Lab member 3 is in this administrative group|
-|Group: Ashton Lab Admin|can_manage |User: Alison |Alison is in this administrative group|
-|Group: Ashton Lab Admin|can_manage |User: George |George is in this administrative group|
-|Alison |can_manage |Group: Ashton Lab Admin |Alison can do everything the above lab members can do|
-|George |can_read |Group: Ashton Lab Admin |George can read everything the above lab members can read|
+h2. Group Membership
-h3. 5. Segregated roles
+Group membership is determined by whether the group has *can_read* permission on an object. If a group G *can_read* an object A, then we say A is a member of G.
-Granwyth, at the Hulatberi Lab, sets up a Factory Robot which uses a hosted Arvados site to do work for the Hulatberi Lab.
+For some kinds of groups, like roles, it is natural for users who are members of a group to also have *can_manage* permission on the group, i.e., G *can_read* A and A *can_manage* G ("A can do anything G can do"). However, this is not necessary: A can be a member of a group while being unable to even read it.
-Frank uploads a data Collection using Factory Robot's upload interface. Factory Robot sets data owner to Hulatberi Lab.
+h2. Special cases
-Factory Robot processes the data using a pipeline.
+* Log table objects are additionally readable based on whether the User has *can_read* permission on @object_uuid@ (User can access log history about objects it can read). To retain the integrity of the log, the log table should deny all update or delete operations.
+* Permission links where @tail_uuid@ is a User permit @can_read@ on the link by that user. (User can discover her own permission grants.)
+* *can_read* on a Collection grants permission to read the blocks that make up the collection (API server returns signed blocks)
+* If User or Group X *can_FOO* Group A, and Group A *can_manage* User B, then X *can_FOO* _everything that User B can_FOO_.
-Factory Robot grants permission for anyone in the Ingeborg Lab (a Hulateberi Lab customer) to read the output of the pipeline, as well as the pipeline invocation details. (Say, Ingeborg and Jill.)
+h2(#system). System user and group
-During and after processing, all members of the Hulatberi Lab (_e.g._, Mike) can inspect pipeline progress, read source/intermediate/output data, and modify objects.
+A privileged user account exists for the use by internal Arvados components. This user manages system objects which should not be "owned" by any particular user. The system user uuid is @{siteprefix}-tpzed-000000000000000@.
-Possible encoding:
+h2. Anoymous user and group
-table(table table-bordered table-condensed).
-|Tail |Permission |Head |Effect|
-|Frank |(none) | |Factory Robot uses only its own credentials during upload|
-|Granwyth |can_manage |User: Factory Robot |can revoke tokens, view activity... (needed?)|
-|Granwyth |can_manage |Group: Hulatberi Lab |can grant group-write permission to Factory Robot|
-|Factory Robot |can_write |Group: Hulatberi Lab |can add data, pipelines, jobs, etc. to the Lab group|
-|Mike |can_write |Group: Hulatberi Lab |can edit/annotate/delete objects that belong to the Lab|
+An Arvado site may be configued to allow users to browse resources without requiring a log in. In this case, permissions for non-logged-in users are associated with the "anonymous" user. To make objects visible to the public, they can be shared with the "anonymous" group. The anonymous user uuid is @{siteprefix}-tpzed-anonymouspublic@. The anonymous group uuid is @{siteprefix}-j7d0g-anonymouspublic@.
-h3. Actions governed by permissions
+h2. Example
-table(table table-bordered table-condensed).
-|_Action_|_Permissions needed_|
-|Retrieve data from Keep|can_read (system-wide?)|
-|Store data in Keep|can_write (system-wide?)|
-|Add a Collection to Arvados|can_write (system-wide?)|
-|Run a job|can_run (system-wide?)|
-|See progress/result of a job|can_read (on job)|
-|Give group permissions to a user/group|can_manage (on group)|
-|Revoke group permissions from a user/group|can_manage (on group)|
-|Change owner of an object|can_manage (on object)|
-|Add an object to a group|can_write (on group)|
+!{{site.baseurl}}/images/Arvados_Permissions.svg!
--- /dev/null
+---
+layout: default
+navsection: api
+navmenu: Concepts
+title: REST API syntax
+...
+
+Arvados exposes a REST API using standard HTTP requests.
+
+h3. HTTP Method
+
+Use @GET@ to request individual resources or lists of resources.
+
+Use @POST@ to create new resources.
+
+Use @PUT@ to update an existing resource.
+
+Use @DELETE@ to remove an existing resource.
+
+As a special case, a @POST@ with the query parameter @_method=GET@ will be treated as a GET request. This makes it possible to issue @GET@ requests where the query string exceeds the maximum request URI length, by putting the query string in the body of the request.
+
+h3. Request URI
+
+The URI portion of the request identifies the specific resource to operate on. For example, operations on "collections":{{site.baseurl}}/api/methods/collections.html use the @https://{{ site.arvados_api_host }}/arvados/v1/collections@ request URI prefix.
+
+h3. Authorization header
+
+Every request must include an API token. This identifies the user making the request for the purposes of access control. In addition, tokens may be further "restricted in scope":{{site.baseurl}}/api/methods/api_client_authorizations.html#scope to only access certain API endpoints.
+
+API requests must provide the API token using the @Authorization@ header in the following format:
+
+<pre>
+$ curl -v -H "Authorization: OAuth2 xxxxapitokenxxxx" https://192.168.5.2:8000/arvados/v1/collections
+> GET /arvados/v1/collections HTTP/1.1
+> ...
+> Authorization: OAuth2 xxxxapitokenxxxx
+> ...
+</pre>
+
+h3. Parameters
+
+Request parameters may be provided in one of two ways. They may be provided in the "query" section of request URI, or they may be provided in the body of the request with application/x-www-form-urlencoded encoding. If parameters are provided in both places, their values will be merged. Parameter names must be unique. If a parameter appears multiple times, the behavior is undefined.
+
+Structured and nested parameter values must be provided as urlencoded JSON.
+
+h3. Result
+
+Results are returned JSON-encoded in the response body.
+
+h3. Errors
+
+If a request cannot be fulfilled, the API will return 4xx or 5xx HTTP status code. Be aware that the API server may return a 404 (Not Found) status for resources that exist but for which the client does not have read access. The API will also return an error record:
+
+table(table table-bordered table-condensed).
+|*Parameter name*|*Value*|*Description*|
+|errors|array|An array of one or more error messages|
+|error_token|string|a unique identifier used to correlate the error in the API server logs|
+
+h2. Examples
+
+h3. Create a new record
+
+<pre>
+$ curl -v -X POST --data-urlencode 'collection={"name":"empty collection"}' -H "Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr" https://192.168.5.2:8000/arvados/v1/collections | jq .
+> POST /arvados/v1/collections HTTP/1.1
+> User-Agent: curl/7.38.0
+> Host: 192.168.5.2:8000
+> Accept: */*
+> Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr
+> Content-Length: 54
+> Content-Type: application/x-www-form-urlencoded
+>
+} [data not shown]
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Status: 200 OK
+< Access-Control-Allow-Origin: *
+< Access-Control-Allow-Methods: GET, HEAD, PUT, POST, DELETE
+< Access-Control-Allow-Headers: Authorization
+< Access-Control-Max-Age: 86486400
+< X-UA-Compatible: IE=Edge,chrome=1
+< ETag: "2ec9ef5151c1f7a1486ad169c33ae462"
+< Cache-Control: max-age=0, private, must-revalidate
+< Set-Cookie: _server_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiJTIwMjQ1NTE5YmEwMzU1MGZkMTBmYmY1YzllY2ZiMjFlBjsAVA%3D%3D--653bc9c20899d48ee8523e18d9a4c1cde0702577; path=/; HttpOnly
+< X-Request-Id: 56aa10bc49097f3b44d3ed946bf0e61e
+< X-Runtime: 0.049951
+< X-Powered-By: Phusion Passenger 4.0.41
+< Date: Fri, 28 Oct 2016 19:20:09 GMT
+< Server: nginx/1.4.7 + Phusion Passenger 4.0.41
+<
+{
+ "href": "/collections/962eh-4zz18-m1ma0mxxfg3mbcc",
+ "kind": "arvados#collection",
+ "etag": "c5ifrv1ox2tu6alb559ymtkb7",
+ "uuid": "962eh-4zz18-m1ma0mxxfg3mbcc",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-10-28T19:20:09.320771531Z",
+ "modified_by_client_uuid": "962eh-ozdt8-lm5x8emraox8epg",
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-10-28T19:20:09.319661000Z",
+ "name": "empty collection",
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "d41d8cd98f00b204e9800998ecf8427e+0",
+ "manifest_text": "",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+}
+</pre>
+
+h3. Delete a record
+
+<pre>
+$ curl -X DELETE -v -H "Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr" https://192.168.5.2:8000/arvados/v1/collections/962eh-4zz18-m1ma0mxxfg3mbcc | jq .
+> DELETE /arvados/v1/collections/962eh-4zz18-m1ma0mxxfg3mbcc HTTP/1.1
+> User-Agent: curl/7.38.0
+> Host: 192.168.5.2:8000
+> Accept: */*
+> Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr
+>
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Status: 200 OK
+< Access-Control-Allow-Origin: *
+< Access-Control-Allow-Methods: GET, HEAD, PUT, POST, DELETE
+< Access-Control-Allow-Headers: Authorization
+< Access-Control-Max-Age: 86486400
+< X-UA-Compatible: IE=Edge,chrome=1
+< ETag: "1e8f72802cf1a6d0a5c4a1ebbfcc46a9"
+< Cache-Control: max-age=0, private, must-revalidate
+< Set-Cookie: _server_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiJTc2NDYyY2M0NTNlNmU3M2Y2M2E3YmFiMWQ1MTEyZGZkBjsAVA%3D%3D--d28c7dd640bd24e2b12f01e77088072138dcf145; path=/; HttpOnly
+< X-Request-Id: e66fd3ab825bdb87301f5456161fb641
+< X-Runtime: 0.028788
+< X-Powered-By: Phusion Passenger 4.0.41
+< Date: Fri, 28 Oct 2016 19:33:31 GMT
+< Server: nginx/1.4.7 + Phusion Passenger 4.0.41
+<
+{
+ "href": "/collections/962eh-4zz18-m1ma0mxxfg3mbcc",
+ "kind": "arvados#collection",
+ "etag": "c5ifrv1ox2tu6alb559ymtkb7",
+ "uuid": "962eh-4zz18-m1ma0mxxfg3mbcc",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-10-28T19:20:09.320771000Z",
+ "modified_by_client_uuid": "962eh-ozdt8-lm5x8emraox8epg",
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-10-28T19:20:09.319661000Z",
+ "name": "empty collection",
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "d41d8cd98f00b204e9800998ecf8427e+0",
+ "manifest_text": "",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+}
+</pre>
+
+h3. Get a specific record
+
+<pre>
+$ curl -v -H "Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr" https://192.168.5.2:8000/arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km | jq .
+> GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km HTTP/1.1
+> User-Agent: curl/7.38.0
+> Host: 192.168.5.2:8000
+> Accept: */*
+> Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr
+>
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Status: 200 OK
+< Access-Control-Allow-Origin: *
+< Access-Control-Allow-Methods: GET, HEAD, PUT, POST, DELETE
+< Access-Control-Allow-Headers: Authorization
+< Access-Control-Max-Age: 86486400
+< X-UA-Compatible: IE=Edge,chrome=1
+< ETag: "fec2ddf433a352e5a2b5d356abd6d3d4"
+< Cache-Control: max-age=0, private, must-revalidate
+< X-Request-Id: 40b447507ff202ae9a0b0b3e0ebe98da
+< X-Runtime: 0.011404
+< X-Powered-By: Phusion Passenger 4.0.41
+< Date: Fri, 28 Oct 2016 18:59:09 GMT
+< Server: nginx/1.4.7 + Phusion Passenger 4.0.41
+<
+{
+ "href": "/collections/962eh-4zz18-xi32mpz2621o8km",
+ "kind": "arvados#collection",
+ "etag": "3mmn0s9e1z5s5opfofmtb9k8p",
+ "uuid": "962eh-4zz18-xi32mpz2621o8km",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-10-27T14:47:43.792587000Z",
+ "modified_by_client_uuid": "962eh-ozdt8-lm5x8emraox8epg",
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-10-27T14:47:43.792166000Z",
+ "name": "Saved at 2016-10-27 14:47:43 UTC by peter@debian",
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "93a45073511646a5c3e2f4953fcf6f61+116",
+ "manifest_text": ". eff999f3b5158331eb44a9a93e3b36e1+67108864+Aad3839bea88bce22cbfe71cf4943de7dab3ea52a@5826180f db141bfd11f7da60dce9e5ee85a988b8+34038725+Ae8f48913fed782cbe463e0499ab37697ee06a2f8@5826180f 0:101147589:rna.SRR948778.bam\n",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+}
+</pre>
+
+h3. List records and filter by date
+
+(Note, return result is truncated).
+
+<pre>
+$ curl -v -G --data-urlencode 'filters=[["created_at",">","2016-11-08T21:38:24.124834000Z"]]' -H "Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr" https://192.168.5.2:8000/arvados/v1/collections | jq .
+> GET /arvados/v1/collections?filters=%5B%5B%22uuid%22%2C%20%22%3D%22%2C%20%22962eh-4zz18-xi32mpz2621o8km%22%5D%5D HTTP/1.1
+> User-Agent: curl/7.38.0
+> Host: 192.168.5.2:8000
+> Accept: */*
+> Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr
+>
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Status: 200 OK
+< Access-Control-Allow-Origin: *
+< Access-Control-Allow-Methods: GET, HEAD, PUT, POST, DELETE
+< Access-Control-Allow-Headers: Authorization
+< Access-Control-Max-Age: 86486400
+< X-UA-Compatible: IE=Edge,chrome=1
+< ETag: "76345ef24952f073acc3a0c550241d4e"
+< Cache-Control: max-age=0, private, must-revalidate
+< X-Request-Id: d34b8ede4ffc707d8ed172dc2f47ff5e
+< X-Runtime: 0.012727
+< X-Powered-By: Phusion Passenger 4.0.41
+< Date: Fri, 28 Oct 2016 19:08:52 GMT
+< Server: nginx/1.4.7 + Phusion Passenger 4.0.41
+<
+{
+ "kind": "arvados#collectionList",
+ "etag": "",
+ "self_link": "",
+ "offset": 0,
+ "limit": 100,
+ "items": [
+ {
+ "href": "/collections/962eh-4zz18-ybggo9im899vv60",
+ "kind": "arvados#collection",
+ "etag": "bvgrrsg63zsenb9wnpnp0nsgl",
+ "uuid": "962eh-4zz18-ybggo9im899vv60",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-11-08T21:47:36.937106000Z",
+ "modified_by_client_uuid": null,
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-11-08T21:47:36.936625000Z",
+ "name": "Log from cwl-runner job 962eh-8i9sb-45jww0k15fi5ldd",
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "a7820b94717eff86229927565fedbd72+85",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+ },
+ ...
+ {
+ "href": "/collections/962eh-4zz18-37i1tfl5de5ild9",
+ "kind": "arvados#collection",
+ "etag": "2fa07dx52lux8wa1loehwyrc5",
+ "uuid": "962eh-4zz18-37i1tfl5de5ild9",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-11-08T21:38:46.717798000Z",
+ "modified_by_client_uuid": null,
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-11-08T21:38:46.717409000Z",
+ "name": null,
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "9d43d4c8328640446f6e252cda584e7e+54",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+ }
+ ],
+ "items_available": 99
+}
+</pre>
+
+h3. Update a field
+
+<pre>
+$ curl -v -X PUT --data-urlencode 'collection={"name":"rna.SRR948778.bam"}' -H "Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr" https://192.168.5.2:8000/arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km | jq .
+> PUT /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km HTTP/1.1
+> User-Agent: curl/7.38.0
+> Host: 192.168.5.2:8000
+> Accept: */*
+> Authorization: OAuth2 oz0os4nyudswvglxhdlnrgnuelxptmj7qu7dpwvyz3g9ocqtr
+> Content-Length: 53
+> Content-Type: application/x-www-form-urlencoded
+>
+} [data not shown]
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Status: 200 OK
+< Access-Control-Allow-Origin: *
+< Access-Control-Allow-Methods: GET, HEAD, PUT, POST, DELETE
+< Access-Control-Allow-Headers: Authorization
+< Access-Control-Max-Age: 86486400
+< X-UA-Compatible: IE=Edge,chrome=1
+< ETag: "fbb50d2847426eab793e3fcf346ca9eb"
+< Cache-Control: max-age=0, private, must-revalidate
+< Set-Cookie: _server_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiJWI3NjFjMzVjMGI5OGExYmNjZDg0ZTg5MjZhMzcwMDE1BjsAVA%3D%3D--0e005d71fad15cb366e47361c38474b7447ba155; path=/; HttpOnly
+< X-Request-Id: 76d3cb3c0995af6133b0a73a64f57354
+< X-Runtime: 0.030756
+< X-Powered-By: Phusion Passenger 4.0.41
+< Date: Fri, 28 Oct 2016 19:15:16 GMT
+< Server: nginx/1.4.7 + Phusion Passenger 4.0.41
+<
+{
+ "href": "/collections/962eh-4zz18-xi32mpz2621o8km",
+ "kind": "arvados#collection",
+ "etag": "51509hhxo9qqjxqewnoz1b7og",
+ "uuid": "962eh-4zz18-xi32mpz2621o8km",
+ "owner_uuid": "962eh-tpzed-000000000000000",
+ "created_at": "2016-10-27T14:47:43.792587000Z",
+ "modified_by_client_uuid": "962eh-ozdt8-lm5x8emraox8epg",
+ "modified_by_user_uuid": "962eh-tpzed-000000000000000",
+ "modified_at": "2016-10-28T19:15:16.137814000Z",
+ "name": "rna.SRR948778.bam",
+ "description": null,
+ "properties": {},
+ "portable_data_hash": "93a45073511646a5c3e2f4953fcf6f61+116",
+ "manifest_text": ". eff999f3b5158331eb44a9a93e3b36e1+67108864+Acca57af82cc18c5dfa47bdfd16e335fccd09dfa5@582618c4 db141bfd11f7da60dce9e5ee85a988b8+34038725+A7764f122f41f92c2d5bde1852fcdd1bea5f8bd78@582618c4 0:101147589:rna.SRR948778.bam\n",
+ "replication_desired": null,
+ "replication_confirmed": null,
+ "replication_confirmed_at": null,
+ "expires_at": null
+}
+</pre>
layout: default
navsection: api
navmenu: Concepts
-title: Resources
+title: Common resource fields
...
-
-
This page describes the common attributes of Arvados resources.
-The list of resource types is on the "front page of the API Reference":./.
-
-h2. Object IDs
-
-Object IDs are alphanumeric strings, unique across all installations (each installation has a unique prefix to prevent collisions).
-
-h2(#resource). Attributes of resources
+h2(#resource). Resource
table(table table-bordered table-condensed).
-|*Attribute*|*Type*|*Description*|*Example*|
-|uuid|string|universally unique object identifier|@mk2qn-4zz18-w3anr2hk2wgfpuo@|
+|_. Attribute |_. Type |_. Description |_. Example|
+|uuid|string|universally unique object identifier, set on @create@|@mk2qn-4zz18-w3anr2hk2wgfpuo@|
+|owner_uuid|string|UUID of owner (must be a User or Group), set on @create@, controls who may access the resource, ownership may be changed explicitly with @update@, see "permission model":{{site.baseurl}}/api/permission-model.html for details.|@mk2qn-tpzed-a4lcehql0dv2u25@|
+|created_at|datetime|When resource was created, set on @create@|@2013-01-21T22:17:39Z@|
+|modified_by_client_uuid|string|API client software which most recently modified the resource, set on @create@ and @update@|@mk2qn-ozdt8-vq8l5qkzj7pr7h7@|
+|modified_by_user_uuid|string|Authenticated user, on whose behalf the client was acting when modifying the resource, set on @create@ and @update@|@mk2qn-tpzed-a4lcehql0dv2u25@|
+|modified_at|datetime|When resource was last modified, set on @create@ and @update@|@2013-01-25T22:29:32Z@|
|href|string|a URL that can be used to address this resource||
|kind|string|@arvados#{resource_type}@|@arvados#collection@|
|etag|string|The ETag[1] of the resource|@1xlmizzjq7wro3dlb2dirf505@|
-|self_link|string|||
-|owner_uuid|string|UUID of owner (typically User or Project)|@mk2qn-tpzed-a4lcehql0dv2u25@|
-|created_at|datetime|When resource was created|@2013-01-21T22:17:39Z@|
-|modified_by_client_uuid|string|API client software which most recently modified the resource|@mk2qn-ozdt8-vq8l5qkzj7pr7h7@|
-|modified_by_user_uuid|string|Authenticated user, on whose behalf the client was acting when modifying the resource|@mk2qn-tpzed-a4lcehql0dv2u25@|
-|modified_at|datetime|When resource was last modified|@2013-01-25T22:29:32Z@|
-h2(#resourceList). Attributes of resource lists
+h2. Object UUID
-table(table table-bordered table-condensed).
-|*Attribute*|*Type*|*Description*|*Example*|
-|kind|string|@arvados#{resource_type}List@|@arvados#projectList@|
-|etag|string|The ETag[1] of the resource list|@cd3o1wi9sf934saajykawrz2e@|
-|self_link|string|||
-|next_page_token|string|||
-|next_link|string|||
-|items[]|list|List of resources||
+Each object is assigned a UUID. This has the format @aaaaa-bbbbb-ccccccccccccccc@.
+
+# The first field (@aaaaa@ in the example) is the site prefix. This is unique to a specific Arvados installation.
+# The second field (@bbbbb@ in the example) is the object type.
+# The third field (@ccccccccccccccc@ in the example) uniquely identifies the object.
+h2. Timestamps
+
+All Arvados timestamps follow ISO 8601 datetime format with fractional seconds (microsecond precision). All timestamps are UTC. Date format: @YYYY-mm-ddTHH:MM:SS.SSSSZ@ example date: @2016-11-08T21:38:24.124834000Z@.
h2. ETags
fn1. Each response includes an ETag, a string which changes when the resource changes. Clients can use this to check whether a resource has changed since they last retrieved it. If a previous ETag is provided along with a request, and the resource has not changed since, the server may return a "not modified" response.
-
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: ApiClient
-
-...
-
-
-An **ApiClient** represents a client program that can issue requests to the API server.
-
-h2. Methods
-
-See "api_clients":{{site.baseurl}}/api/methods/api_clients.html
-
-h2. Resource
-
-Each ApiClient has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|url_prefix|string|||
-|is_trusted|boolean|Trusted by users to handle their API tokens (ApiClientAuthorizations).||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: ApiClientAuthorization
-
-...
-
-An **ApiClientAuthorization** represents an API client's authorization to make API requests on a user's behalf.
-
-h2. Methods
-
-See "api_client_authorizations":{{site.baseurl}}/api/methods/api_client_authorizations.html
-
-h2. Resource
-
-An ApiClientAuthorization is not a generic Arvados resource. The full list of properties that belong to an ApiClientAuthorization is:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|api_token|string|||
-|api_client_id|integer|||
-|user_id|integer|||
-|created_by_ip_address|string|||
-|last_used_by_ip_address|string|||
-|last_used_at|datetime|||
-|expires_at|datetime|||
-|default_owner_uuid|string|||
-|scopes|array|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: AuthorizedKey
-...
-
-An **AuthorizedKey** represents the public part of an SSH authentication key which can be used to authorize transactions on behalf of the user.
-
-h2. Methods
-
-See "authorized_keys":{{site.baseurl}}/api/methods/authorized_keys.html
-
-h2. Resource
-
-Each AuthorizedKey has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|key_type|string|||
-|authorized_user_uuid|string|||
-|public_key|text|||
-|expires_at|datetime|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Collection
-
-...
-
-Note: This resource concerns indexing, usage accounting, and integrity checks for data stored in Arvados. Reading and writing the data _per se_ is achieved by the "Keep":{{site.baseurl}}/user/tutorials/tutorial-keep.html storage system.
-
-h2. Methods
-
-See "collections":{{site.baseurl}}/api/methods/collections.html
-
-h3. Conditions of creating a Collection
-
-The @uuid@ and @manifest_text@ attributes must be provided when creating a Collection. The cryptographic digest of the supplied @manifest_text@ must match the supplied @uuid@.
-
-h3. Side effects of creating a Collection
-
-Referenced data can be protected from garbage collection. See the section about "resources" links on the "Links":Link.html page.
-
-Data can be shared with other users via the Arvados permission model.
-
-Clients can request checks of data integrity and storage redundancy.
-
-h2. Resource
-
-Each collection has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|description|text|||
-|portable_data_hash|string|||
-|manifest_text|text|||
-|replication_desired|number|Minimum storage replication level desired for each data block referenced by this collection. A value of @null@ signifies that the site default replication level (typically 2) is desired.|@2@|
-|replication_confirmed|number|Replication level most recently confirmed by the storage system. This field is null when a collection is first created, and is reset to null when the manifest_text changes in a way that introduces a new data block. An integer value indicates the replication level of the _least replicated_ data block in the collection.|@2@, null|
-|replication_confirmed_at|datetime|When replication_confirmed was confirmed. If replication_confirmed is null, this field is also null.||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Container
-
-...
-
-A Container:
-* Precisely describes the environment in which a Crunch2 process should run. For example, git trees, data collections, and docker images are stored as content addresses. This makes it possible to reason about the difference between two processes, and to replay a process at a different time and place.
-* Container records are created by the system to fulfill container requests.
-
-h2. Methods
-
-See "containers":{{site.baseurl}}/api/methods/containers.html
-
-h2. Resource
-
-Each Container offers the following attributes, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Notes|
-|state|string|The allowed states are "Queued", "Locked", "Running", "Cancelled" and "Complete".|See "Container states":#container_states for more details.|
-|started_at|datetime|When this container started running.|Null if container has not yet started.|
-|finished_at|datetime|When this container finished.|Null if container has not yet finished.|
-|log|string|Portable data hash of the collection containing logs from a completed container run.|Null if the container is not yet finished.|
-|environment|hash|Environment variables and values that should be set in the container environment (@docker run --env@). This augments and (when conflicts exist) overrides environment variables given in the image's Dockerfile.|Must be equal to a ContainerRequest's environment in order to satisfy the ContainerRequest.|
-|cwd|string|Initial working directory.|Must be equal to a ContainerRequest's cwd in order to satisfy the ContainerRequest|
-|command|array of strings|Command to execute.| Must be equal to a ContainerRequest's command in order to satisfy the ContainerRequest.|
-|output_path|string|Path to a directory or file inside the container that should be preserved as this container's output when it finishes.|Must be equal to a ContainerRequest's output_path in order to satisfy the ContainerRequest.|
-|mounts|hash|Must contain the same keys as the ContainerRequest being satisfied. Each value must be within the range of values described in the ContainerRequest at the time the Container is assigned to the ContainerRequest.|See "Mount types":#mount_types for more details.|
-|runtime_constraints|hash|Compute resources, and access to the outside world, that are / were available to the container.
-Generally this will contain additional keys that are not present in any corresponding ContainerRequests: for example, even if no ContainerRequests specified constraints on the number of CPU cores, the number of cores actually used will be recorded here.|e.g.,
-<pre><code>{
- "ram":12000000000,
- "vcpus":2,
- "API":true
-}</code></pre>See "Runtime constraints":#runtime_constraints for more details.|
-|output|string|Portable data hash of the output collection.|Null if the container is not yet finished.|
-|container_image|string|Portable data hash of a collection containing the docker image used to run the container.||
-|progress|number|A number between 0.0 and 1.0 describing the fraction of work done.||
-|priority|integer|Priority assigned by the system, taking into account the priorities of all associated ContainerRequests.||
-|exit_code|integer|Process exit code.|Null if state!="Complete"|
-|auth_uuid|string|UUID of a token to be passed into the container itself, used to access Keep-backed mounts, etc.|Null if state∉{"Locked","Running"}|
-|locked_by_uuid|string|UUID of a token, indicating which dispatch process changed state to Locked. If null, any token can be used to lock. If not null, only the indicated token can modify this container.|Null if state∉{"Locked","Running"}|
-
-h2(#container_states). Container states
-
-table(table table-bordered table-condensed).
-|_. State|_. Sgnificance|_. Allowed next|
-|Queued|Waiting for a dispatcher to lock it and try to run the container.|Locked, Cancelled|
-|Locked|A dispatcher has "taken" the container and is allocating resources for it. The container has not started yet.|Queued, Running, Cancelled|
-|Running|Resources have been allocated and the contained process has been started (or is about to start). Crunch-run _must_ set state to Running _before_ there is any possibility that user code will run in the container.|Complete, Cancelled|
-|Complete|Container was running, and the contained process/command has exited.|-|
-|Cancelled|The container did not run long enough to produce an exit code. This includes cases where the container didn't even start, cases where the container was interrupted/killed before it exited by itself (e.g., priority changed to 0), and cases where some problem prevented the system from capturing the contained process's exit status (exit code and output).|-|
-
-h2(#mount_types). {% include 'mount_types' %}
-
-h2(#runtime_constraints). {% include 'container_runtime_constraints' %}
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: ContainerRequest
-
-...
-
-A ContainerRequest:
-* Is a client's expression of interest in knowing the outcome of a computational process.
-* The system is responsible for finding suitable containers and assigning them to container_requests.
-* The client's description of the ContainerRequest is less precise than of a Container: a ContainerRequest describes container constraints which can have different interpretations over time. For example, a ContainerRequest with a {"kind":"git_tree","commit_range":"abc123..master",...} mount might be satisfiable by any of several different source trees, and this set of satisfying source trees can change when the repository's "master" branch is updated.
-
-h2. Methods
-
-See "container_requests":{{site.baseurl}}/api/methods/container_requests.html
-
-h2. Resource
-
-Each ContainerRequest offers the following attributes, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-All attributes are optional, unless otherwise marked as required.
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Notes|
-|name|string|The name of the container_request.||
-|description|string|The description of the container_request.||
-|properties|hash|Client-defined structured data that does not affect how the container is run.||
-|state|string|The allowed states are "Uncommitted", "Committed", and "Final".|Once a request is Committed, the only attributes that can be modified are priority, container_uuid, and container_count_max. A request in the "Final" state cannot have any of its functional parts modified (i.e., only name, description, and properties fields can be modified).|
-|requesting_container_uuid|string|The uuid of the parent container that created this container_request, if any. Represents a process tree.|The priority of this container_request is inherited from the parent container, if the parent container is cancelled, this container_request will be cancelled as well.|
-|container_uuid|string|The uuid of the container that satisfies this container_request. The system will find and reuse any preexisting Container that matches this ContainerRequest's criteria. See "Container reuse":#container_reuse for more details.|Currently, container reuse is the default behavior and a mechanism to skip reuse is not supported.|
-|container_count_max|integer|Maximum number of containers to start, i.e., the maximum number of "attempts" to be made.||
-|mounts|hash|Objects to attach to the container's filesystem and stdin/stdout.|See "Mount types":#mount_types for more details.|
-|runtime_constraints|hash|Restrict the container's access to compute resources and the outside world.|Required when in "Committed" state. e.g.,<pre><code>{
- "ram":12000000000,
- "vcpus":2,
- "API":true
-}</code></pre>See "Runtime constraints":#runtime_constraints for more details.|
-|container_image|string|Portable data hash of a collection containing the docker image to run the container.|Required.|
-|environment|hash|Environment variables and values that should be set in the container environment (@docker run --env@). This augments and (when conflicts exist) overrides environment variables given in the image's Dockerfile.||
-|cwd|string|Initial working directory, given as an absolute path (in the container) or a path relative to the WORKDIR given in the image's Dockerfile.|Required.|
-|command|array of strings|Command to execute in the container.|Required. e.g., @["echo","hello"]@|
-|output_path|string|Path to a directory or file inside the container that should be preserved as container's output when it finishes. This path must be, or be inside, one of the mount targets. For best performance, point output_path to a writable collection mount.|Required.|
-|priority|integer|Higher value means spend more resources on this container_request, i.e., go ahead of other queued containers, bring up more nodes etc.|Priority 0 means a container should not be run on behalf of this request. Clients are expected to submit ContainerRequests with zero priority in order to prevew the container that will be used to satisfy it. Priority can be null if and only if state!="Committed".|
-|expires_at|datetime|After this time, priority is considered to be zero.|Not yet implemented.|
-|filters|string|Additional constraints for satisfying the container_request, given in the same form as the filters parameter accepted by the container_requests.list API.||
-
-h2(#mount_types). {% include 'mount_types' %}
-
-h2(#runtime_constraints). {% include 'container_runtime_constraints' %}
-
-h2(#container_reuse). Container reuse
-
-When a ContainerRequest is "Committed", the system will try to find and reuse any preexisting Container with the same exact command, cwd, environment, output_path, container_image, mounts, and runtime_constraints as this ContainerRequest. The serialized fields environment, mounts and runtime_constraints are sorted to facilitate comparison.
-
-The system will use the following scheme to determine which Container to consider for reuse: A Container with the same exact command, cwd, environment, output_path, container_image, mounts, and runtime_constraints as this ContainerRequest and,
-* The oldest successfully finished container, i.e., in state "Complete" with exit_code of 0. If matching containers with different outputs are found, the system will forgo reusing any of these finished containers and instead look for suitable containers in other states
-* The oldest "Running" container with the highest progress, i.e., the container that is most likely to finish first
-* The oldest "Locked" container with the highest priority, i.e., the container that is most likely to start first
-* The oldest "Queued" container with the highest priority, i.e, the container that is most likely to start first
-
-{% include 'notebox_begin' %}
-Currently, container reuse is the default behavior and a mechanism to skip reuse is not supported.
-{% include 'notebox_end' %}
-
-h2(#cancel_container). Canceling a ContainerRequest
-
-A ContainerRequest may be canceled by setting it's priority to 0, using an update call.
-
-When a ContainerRequest is canceled, it will still reflect the state of the Container it is associated with via the container_uuid attribute. If that Container is being reused by any other container_requests that are still active, i.e., not yet canceled, that Container may continue to run or be scheduled to run by the system in future. However, if no other container_requests are using that Contianer, then the Container will get canceled as well.
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Group
-
-...
-
-A **Group** represents a set of objects. Groups allow you to organize content, define user roles, and apply permissions to sets of objects.
-
-h2. Methods
-
-See "groups":{{site.baseurl}}/api/methods/groups.html
-
-h2. Resource
-
-Each Group has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|group_class|string|Type of group. This does not affect behavior, but determines how the group is presented in the user interface. For example, @project@ indicates that the group should be displayed by Workbench and arv-mount as a project for organizing and naming objects.|@"project"@
-null|
-|description|text|||
-|writable_by|array|List of UUID strings identifying Users and other Groups that have write permission for this Group. Only users who are allowed to administer the Group will receive a full list. Other users will receive a partial list that includes the Group's owner_uuid and (if applicable) their own user UUID.||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Human
-
-...
-
-h2. Methods
-
-See "humans":{{site.baseurl}}/api/methods/humans.html
-
-h2. Resource
-
-Each Human has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|properties|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Job
-
-...
-
-Applications submit compute jobs when:
-* Provenance is important, i.e., it is worth recording how the output was produced; or
-* Computation time is significant; or
-* The job management features are convenient (failure detection/recovery, regression testing, etc).
-
-h2. Methods
-
-See "jobs":{{site.baseurl}}/api/methods/jobs.html
-
-h2. Resource
-
-Each job has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Notes|
-|script|string|The filename of the job script.|This program will be invoked by Crunch for each job task. It is given as a path to an executable file, relative to the @/crunch_scripts@ directory in the Git tree specified by the _repository_ and _script_version_ attributes.|
-|script_parameters|hash|The input parameters for the job.|Conventionally, one of the parameters is called @"input"@. Typically, some parameter values are collection UUIDs. Ultimately, though, the significance of parameters is left entirely up to the script itself.|
-|repository|string|Git repository name or URL.|Source of the repository where the given script_version is to be found. This can be given as the name of a locally hosted repository, or as a publicly accessible URL starting with @git://@, @http://@, or @https://@.
-Examples:
-@yourusername/yourrepo@
-@https://github.com/curoverse/arvados.git@|
-|script_version|string|Git commit|During a **create** transaction, this is the Git branch, tag, or hash supplied by the client. Before the job starts, Arvados updates it to the full 40-character SHA-1 hash of the commit used by the job.
-See "Specifying Git versions":#script_version below for more detail about acceptable ways to specify a commit.|
-|cancelled_by_client_uuid|string|API client ID|Is null if job has not been cancelled|
-|cancelled_by_user_uuid|string|Authenticated user ID|Is null if job has not been cancelled|
-|cancelled_at|datetime|When job was cancelled|Is null if job has not been cancelled|
-|started_at|datetime|When job started running|Is null if job has not [yet] started|
-|finished_at|datetime|When job finished running|Is null if job has not [yet] finished|
-|running|boolean|Whether the job is running||
-|success|boolean|Whether the job indicated successful completion|Is null if job has not finished|
-|is_locked_by_uuid|string|UUID of the user who has locked this job|Is null if job is not locked. The system user locks the job when starting the job, in order to prevent job attributes from being altered.|
-|node_uuids|array|List of UUID strings for node objects that have been assigned to this job||
-|log|string|Collection UUID|Is null if the job has not finished. After the job runs, the given collection contains a text file with log messages provided by the @arv-crunch-job@ task scheduler as well as the standard error streams provided by the task processes.|
-|tasks_summary|hash|Summary of task completion states.|Example: @{"done":0,"running":4,"todo":2,"failed":0}@|
-|output|string|Collection UUID|Is null if the job has not finished.|
-|nondeterministic|boolean|The job is expected to produce different results if run more than once.|If true, this job will not be considered as a candidate for automatic re-use when submitting subsequent identical jobs.|
-|submit_id|string|Unique ID provided by client when job was submitted|Optional. This can be used by a client to make the "jobs.create":{{site.baseurl}}/api/methods/jobs.html#create method idempotent.|
-|priority|string|||
-|arvados_sdk_version|string|Git commit hash that specifies the SDK version to use from the Arvados repository|This is set by searching the Arvados repository for a match for the arvados_sdk_version runtime constraint.|
-|docker_image_locator|string|Portable data hash of the collection that contains the Docker image to use|This is set by searching readable collections for a match for the docker_image runtime constraint.|
-|runtime_constraints|hash|Constraints that must be satisfied by the job/task scheduler in order to run the job.|See below.|
-|components|hash|Name and uuid pairs representing the child work units of this job. The uuids can be of different object types.|Example components hash: @{"name1": "zzzzz-8i9sb-xyz...", "name2": "zzzzz-d1hrv-xyz...",}@|
-
-h3(#script_version). Specifying Git versions
-
-The script_version attribute and arvados_sdk_version runtime constraint are typically given as a branch, tag, or commit hash, but there are many more ways to specify a Git commit. The "specifying revisions" section of the "gitrevisions manual page":http://git-scm.com/docs/gitrevisions.html has a definitive list. Arvados accepts Git versions in any format listed there that names a single commit (not a tree, a blob, or a range of commits). However, some kinds of names can be expected to resolve differently in Arvados than they do in your local repository. For example, <code>HEAD@{1}</code> refers to the local reflog, and @origin/master@ typically refers to a remote branch: neither is likely to work as desired if given as a Git version.
-
-h3. Runtime constraints
-
-table(table table-bordered table-condensed).
-|_. Key|_. Type|_. Description|_. Implemented|
-|arvados_sdk_version|string|The Git version of the SDKs to use from the Arvados git repository. See "Specifying Git versions":#script_version for more detail about acceptable ways to specify a commit. If you use this, you must also specify a @docker_image@ constraint (see below). In order to install the Python SDK successfully, Crunch must be able to find and run virtualenv inside the container.|✓|
-|docker_image|string|The Docker image that this Job needs to run. If specified, Crunch will create a Docker container from this image, and run the Job's script inside that. The Keep mount and work directories will be available as volumes inside this container. The image must be uploaded to Arvados using @arv keep docker@. You may specify the image in any format that Docker accepts, such as @arvados/jobs@, @debian:latest@, or the Docker image id. Alternatively, you may specify the portable data hash of the image Collection.|✓|
-|min_nodes|integer||✓|
-|max_nodes|integer|||
-|min_cores_per_node|integer|Require that each node assigned to this Job have the specified number of CPU cores|✓|
-|min_ram_mb_per_node|integer|Require that each node assigned to this Job have the specified amount of real memory (in MiB)|✓|
-|min_scratch_mb_per_node|integer|Require that each node assigned to this Job have the specified amount of scratch storage available (in MiB)|✓|
-|max_tasks_per_node|integer|Maximum simultaneous tasks on a single node|✓|
-|keep_cache_mb_per_task|integer|Size of file data buffer for per-task Keep directory ($TASK_KEEPMOUNT), in MiB. Default is 256 MiB. Increase this to reduce cache thrashing in situtations such as accessing multiple large (64+ MiB) files at the same time, or accessing different parts of a large file at the same time.|✓|
-|min_ram_per_task|integer|Minimum real memory (KiB) per task||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: JobTask
-
-...
-
-A Job Task is a well defined independently-computable portion of a "Job":Job.html.
-
-Job tasks are created two ways:
-* When a job starts, it is seeded with a job task with @sequence=0@ and an empty @parameters{}@ list.
-* Job task A can create additional job tasks B, C, D, which will belong to the same job. Tasks B, C, D will not be performed until job task A is complete. If job task A fails, tasks B, C, D will be deleted.
-
-Job tasks have particular update semantics:
-* Progress reporting: A job task should only be <code>PATCH</code>ed by a worker process which has been dispatched to work on that task and is reporting progress or completion status — and by the job manager itself.
-* Completion: When a job task process terminates, the task is considered complete only if its most recent @PATCH@ transaction had @progress=1.0@ and @success=true@.
-* Temporary failure: If a job task process terminates without updating @success@ to @true@ or @false@, it is assumed that the task failed but is worth re-attempting (at a different time, on a different node, etc).
-
-
-h2. Methods
-
-See "job_tasks":{{site.baseurl}}/api/methods/job_tasks.html
-
-h2. Resource
-
-Each JobTask has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|sequence|integer|Execution sequence.
-A step cannot be run until all steps with lower sequence numbers have completed.
-Job steps with the same sequence number can be run in any order.||
-|parameters|hash|||
-|output|text|||
-|progress|float|||
-|success|boolean|Is null if the task has neither completed successfully nor failed permanently.||
-
-The following attributes should not be updated by anyone other than the job manager:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Notes|
-|qsequence|integer|Order of arrival|0-based|
-|job_uuid|string|||
-|created_by_job_task_uuid|string|||
-
-
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: KeepDisk
-
-...
-
-A **KeepDisk** is a filesystem volume used by a Keep storage server to store data blocks.
-
-h2. Methods
-
-See "keep_disks":{{site.baseurl}}/api/methods/keep_disks.html
-
-h2. Resource
-
-Each KeepDisk has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|ping_secret|string|||
-|node_uuid|string|||
-|filesystem_uuid|string|||
-|bytes_total|integer|||
-|bytes_free|integer|||
-|is_readable|boolean|||
-|is_writable|boolean|||
-|last_read_at|datetime|||
-|last_write_at|datetime|||
-|last_ping_at|datetime|||
-|keep_service_uuid|string|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: KeepService
-
-...
-
-A **KeepService** is a service endpoint that supports the Keep protocol.
-
-h2. Methods
-
-See "keep_services":{{site.baseurl}}/api/methods/keep_services.html
-
-h2. Resource
-
-Each KeepService has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|service_host|string|||
-|service_port|integer|||
-|service_ssl_flag|boolean|||
-|service_type|string|||
\ No newline at end of file
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Link
-
-...
-
-**Links** describe relationships between Arvados objects, and from objects to primitives.
-
-Links are directional: each metadata object has a tail (the "subject" being described), class, name, properties, and head (the "object" that describes the "subject"). A Link may describe a relationship between two objects in an Arvados database: e.g. a _permission_ link between a User and a Group defines the permissions that User has to read or modify the Group. Other Links simply represent metadata for a single object, e.g. the _identifier_ Link, in which the _name_ property represents a human-readable identifier for the object at the link's head.
-
-For links that don't make sense to share between API clients, a _link_class_ that begins with @client@ (like @client.my_app_id@ or @client.my_app_id.anythinghere@) should be used.
-
-h2. Methods
-
-See "links":{{site.baseurl}}/api/methods/links.html
-
-h2. Resource
-
-Each link has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|
-|tail_uuid|string|Object UUID at the tail (start, source, origin) of this link|
-|link_class|string|Class (see below)|
-|name|string|Link type (see below)|
-|head_uuid|string|Object UUID at the head (end, destination, target) of this link|
-|properties|hash|Additional information, expressed as a key→value hash. Key: string. Value: string, number, array, or hash.|
-
-h2. Link classes
-
-Some classes are pre-defined by convention and have standard meanings attached to names.
-
-h3. provenance
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|_. Notes|
-|→Collection |provided → _collection uuid_
-{url→http://example.com/foo.tgz, retrieved_at→1352616640.000}||
-|Job→Collection |provided → _collection uuid_||
-|Specimen→Collection|provided → _collection uuid_||
-|Human→Specimen |provided → _specimen uuid_||
-|Human→Collection |provided → _collection uuid_||
-
-h3. permission
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|_. Notes|
-|User→Group |{white-space:nowrap}. can_manage → _group uuid_|The User can read, write, and control permissions on the Group itself, every object owned by the Group, and every object on which the Group has _can_manage_ permission.|
-|User→Group |can_read → _group uuid_ |The User can retrieve the Group itself and every object that is readable by the Group.|
-|User→Job|can_write → _job uuid_ |The User can read and update the Job. (This works for all objects, not just jobs.)|
-|User→Job|can_manage → _job uuid_ |The User can read, update, and change permissions for the Job. (This works for all objects, not just jobs.)|
-|Group→Job|can_manage → _job uuid_ |Anyone with _can_manage_ permission on the Group can also read, update, and change permissions for the Job. Anyone with _can_read_ permission on the Group can read the Job. (This works for all objects, not just jobs.)|
-
-h3. resources
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|_. Notes|
-|User→Collection|wants → _collection uuid_ |Determines whether data can be deleted|
-|User→Job |wants → _job uuid_ |Determines whether a job can be cancelled|
-
-h3. tag
-
-A **tag** link describes an object using an unparsed plain text string. Tags can be used to annotate objects that are not editable, like collections and objects shared as read-only.
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|
-|→Collection | _tag name_ → _collection uuid_|
-|→Job | _tag name_ → _job uuid_|
-
-h3. human_trait
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|_. Notes|
-|Human→Trait |measured → _trait uuid_ {value→1.83, unit→metre, measured_at→1352616640.000}||
-
-h3. identifier
-
-table(table table-bordered table-condensed).
-|_. tail_type→head_type|_. name→head_uuid {properties}|_. Notes|
-|→Human |hu123456 → _human uuid_||
-
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Log
-
-...
-
-**Log** objects record events that occur in an Arvados cluster. Both user-written pipelines and the Arvados system itself may generate Log events.
-
-h2. Methods
-
-See "logs":{{site.baseurl}}/api/methods/logs.html
-
-h2. Creation
-
-Any user may create Log entries for any event they find useful. User-generated Logs have no intrinsic meaning to other users or to the Arvados system itself; it is up to each user to choose appropriate log event types and summaries for their project.
-
-h3. System Logs
-
-Arvados uses Logs to record creation, deletion, and updates of other Arvados resources.
-
-h2. Resource
-
-Each Log has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|object_uuid|string|||
-|event_at|datetime|||
-|event_type|string|A user-defined category or type for this event.|@LOGIN@|
-|summary|text|||
-|properties|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Node
-
-...
-
-A **Node** represents a host that can be used to run Crunch job tasks.
-
-h2. Methods
-
-See "nodes":{{site.baseurl}}/api/methods/nodes.html
-
-h2. Resource
-
-Each Node has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|slot_number|integer|||
-|hostname|string|||
-|domain|string|||
-|ip_address|string|||
-|job_uuid|string|The UUID of the job that this node is assigned to work on. If you do not have permission to read the job, this will be null.||
-|first_ping_at|datetime|||
-|last_ping_at|datetime|||
-|info|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: PipelineInstance
-
-...
-
-A **PipelineInstance** is the act or record of applying a pipeline template to a specific set of inputs; generally, a pipeline instance refers to a set of jobs that have been run to satisfy the pipeline components.
-
-h2. Methods
-
-See "pipeline_instances":{{site.baseurl}}/api/methods/pipeline_instances.html
-
-h2. Resource
-
-Each PipelineInstance has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|pipeline_template_uuid|string|||
-|name|string|||
-|components|hash|||
-|success|boolean|||
-|active|boolean|||
-|properties|Hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: PipelineTemplate
-...
-
-The pipeline template consists of "name" and "components".
-
-table(table table-bordered table-condensed).
-|_. Attribute |_. Type |_. Accepted values |_. Required|_. Description|
-|name |string |any |yes |The human-readable name of the pipeline template.|
-|components |object |JSON object containing job submission objects|yes |The component jobs that make up the pipeline, with the component name as the key. |
-
-h3. Components
-
-The components field of the pipeline template is a JSON object which describes the individual steps that make up the pipeline. Each component is an Arvados job submission. "Parameters for job submissions are described on the job method page.":{{site.baseurl}}/api/methods/jobs.html#create In addition, a component can have the following parameters:
-
-table(table table-bordered table-condensed).
-|_. Attribute |_. Type |_. Accepted values |_. Required|_. Description|
-|output_name |string or boolean|string or false |no |If a string is provided, use this name for the output collection of this component. If the value is false, do not create a permanent output collection (an temporary intermediate collection will still be created). If not provided, a default name will be assigned to the output.|
-
-h3. Script parameters
-
-When used in a pipeline, each parameter in the 'script_parameters' attribute of a component job can specify that the input parameter must be supplied by the user, or the input parameter should be linked to the output of another component. To do this, the value of the parameter should be JSON object containing one of the following attributes:
-
-table(table table-bordered table-condensed).
-|_. Attribute |_. Type |_. Accepted values |_. Description|
-|default |any |any |The default value for this parameter.|
-|required |boolean |true or false |Specifies whether the parameter is required to have a value or not.|
-|dataclass |string |One of 'Collection', 'File' [1], 'number', or 'text' |Data type of this parameter.|
-|search_for |string |any string |Substring to use as a default search string when choosing inputs.|
-|output_of |string |the name of another component in the pipeline |Specifies that the value of this parameter should be set to the 'output' attribute of the job that corresponds to the specified component.|
-|title |string |any string |User friendly title to display when choosing parameter values|
-|description |string |any string |Extended text description for describing expected/valid values for the script parameter|
-|link_name |string |any string |User friendly name to display for the parameter value instead of the actual parameter value|
-
-The 'output_of' parameter is especially important, as this is how components are actually linked together to form a pipeline. Component jobs that depend on the output of other components do not run until the parent job completes and has produced output. If the parent job fails, the entire pipeline fails.
-
-fn1. The 'File' type refers to a specific file within a Keep collection in the form 'collection_hash/filename', for example '887cd41e9c613463eab2f0d885c6dd96+83/bob.txt'.
-
-The 'search_for' parameter is meaningful only when input dataclass of type Collection or File is used. If a value is provided, this will be preloaded into the input data chooser dialog in Workbench. For example, if your input dataclass is a File and you are interested in a certain filename extention, you can preconfigure it in this attribute.
-
-h3. Examples
-
-This is a pipeline named "Filter MD5 hash values" with two components, "do_hash" and "filter". The "input" script parameter of the "do_hash" component is required to be filled in by the user, and the expected data type is "Collection". This also specifies that the "input" script parameter of the "filter" component is the output of "do_hash", so "filter" will not run until "do_hash" completes successfully. When the pipeline runs, past jobs that meet the criteria described above may be substituted for either or both components to avoid redundant computation.
-
-<notextile><pre>
-{
- "name": "Filter MD5 hash values",
- "components": {
- "do_hash": {
- "script": "hash.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": {
- "input": {
- "required": true,
- "dataclass": "Collection",
- "search_for": ".fastq.gz",
- "title":"Please select a fastq file"
- }
- },
- },
- "filter": {
- "script": "0-filter.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": {
- "input": {
- "output_of": "do_hash"
- }
- },
- }
- }
-}
-</pre></notextile>
-
-This pipeline consists of three components. The components "thing1" and "thing2" both depend on "cat_in_the_hat". Once the "cat_in_the_hat" job is complete, both "thing1" and "thing2" can run in parallel, because they do not depend on each other.
-
-<notextile><pre>
-{
- "name": "Wreck the house",
- "components": {
- "cat_in_the_hat": {
- "script": "cat.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": { }
- },
- "thing1": {
- "script": "thing1.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": {
- "input": {
- "output_of": "cat_in_the_hat"
- }
- },
- },
- "thing2": {
- "script": "thing2.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": {
- "input": {
- "output_of": "cat_in_the_hat"
- }
- },
- },
- }
-}
-</pre></notextile>
-
-This pipeline consists of three components. The component "cleanup" depends on "thing1" and "thing2". Both "thing1" and "thing2" are started immediately and can run in parallel, because they do not depend on each other, but "cleanup" cannot begin until both "thing1" and "thing2" have completed.
-
-<notextile><pre>
-{
- "name": "Clean the house",
- "components": {
- "thing1": {
- "script": "thing1.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": { }
- },
- "thing2": {
- "script": "thing2.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": { }
- },
- "cleanup": {
- "script": "cleanup.py",
- "repository": "<b>you</b>/<b>you</b>",
- "script_version": "master",
- "script_parameters": {
- "mess1": {
- "output_of": "thing1"
- },
- "mess2": {
- "output_of": "thing2"
- }
- }
- }
- }
-}
-</pre></notextile>
-
-h2. Methods
-
-See "pipeline_templates":{{site.baseurl}}/api/methods/pipeline_templates.html
-
-h2. Resource
-
-Each PipelineTemplate has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|components|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Repository
-
-...
-
-A **Repository** represents a git repository hosted in an Arvados installation.
-
-h2. Methods
-
-See "repositories":{{site.baseurl}}/api/methods/repositories.html
-
-h2. Resource
-
-Each Repository has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|The name of the repository on disk. Repository names must begin with a letter and contain only alphanumerics. Unless the repository is owned by the system user, the name must begin with the owner's username, then be separated from the base repository name with @/@. You may not create a repository that is owned by a user without a username.|@username/project1@|
-|clone_urls|array|URLs from which the repository can be cloned. Read-only.|@["git@git.zzzzz.arvadosapi.com:foo/bar.git",
- "https://git.zzzzz.arvadosapi.com/foo/bar.git"]@|
-|fetch_url|string|URL suggested as a fetch-url in git config. Deprecated. Read-only.||
-|push_url|string|URL suggested as a push-url in git config. Deprecated. Read-only.||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Specimen
-
-...
-
-A **Specimen** represents a tissue sample or similar material obtained from a human that has some biomedical significance or interest.
-
-h2. Methods
-
-See "specimens":{{site.baseurl}}/api/methods/specimens.html
-
-h2. Resource
-
-Each Specimen has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|material|string|||
-|properties|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Trait
-
-...
-
-A **Trait** represents a measured or observed characteristic of a human.
-
-h2. Methods
-
-See "traits":{{site.baseurl}}/api/methods/traits.html
-
-h2. Resource
-
-Each Trait has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|||
-|properties|hash|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: User
-
-...
-
-A **User** represents a person who interacts with Arvados via an ApiClient.
-
-h2. Methods
-
-See "users":{{site.baseurl}}/api/methods/users.html
-
-h2. Resource
-
-Each User has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|email|string|||
-|username|string|The username used for the user's git repositories and virtual machine logins. Usernames must start with a letter, and contain only alphanumerics. When a new user is created, a default username is set from their e-mail address. Only administrators may change the username.||
-|first_name|string|||
-|last_name|string|||
-|identity_url|string|||
-|is_admin|boolean|||
-|prefs|hash|||
-|default_owner_uuid|string|||
-|is_active|boolean|||
-|writable_by|array|List of UUID strings identifying Groups and other Users that can modify this User object. This will include the user's owner_uuid and, for administrators and users requesting their own User object, the requesting user's UUID.||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: VirtualMachine
-
-...
-
-A **VirtualMachine** represents a network host, running within an Arvados installation, on which Arvados users are given login accounts.
-
-h2. Methods
-
-See "virtual_machines":{{site.baseurl}}/api/methods/virtual_machines.html
-
-h2. Resource
-
-Each VirtualMachine has, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|hostname|string|||
+++ /dev/null
----
-layout: default
-navsection: api
-navmenu: Schema
-title: Workflow
-
-...
-
-A *Workflow* is a definition of work to be performed by a Crunch2 process. It defines the steps and inputs for the process.
-
-h2. Methods
-
-See "workflows":{{site.baseurl}}/api/methods/workflows.html
-
-h2. Resource
-
-Each Workflow offers the following optional attributes, in addition to the usual "attributes of Arvados resources":{{site.baseurl}}/api/resources.html:
-
-table(table table-bordered table-condensed).
-|_. Attribute|_. Type|_. Description|_. Example|
-|name|string|If not specified, will be set to any "name" from the "definition" attribute.||
-|description|string|If not specified, will be set to any "description" from the "definition" attribute.||
-|definition|string|A "Common Workflow Language" document.|Visit "Common Workflow Language":http://www.commonwl.org/ for details.|
--- /dev/null
+---
+layout: default
+navsection: api
+title: Storage in Keep
+...
+
+Keep clients are applications such as @arv-get@, @arv-put@ and @arv-mount@ which store and retrieve data from Keep. In doing so, these programs interact with both the API server (which stores file metadata in form of Collection objects) and individual Keep servers (which store the actual data blocks).
+
+!{{site.baseurl}}/images/Keep_reading_writing_block.svg!
+
+h2. Storing a file
+
+# The client discovers keep servers (or proxies) using the @accessible@ method on "keep_services":{{site.baseurl}}/api/methods/keep_services.html
+# Data is split into 64 MiB blocks and the MD5 hash is computed for each block.
+# The client uploads each block to one or more Keep servers, based on the number of desired replicas. The priority order is determined using rendezvous hashing, described below.
+# The Keep server returns a block locator (the MD5 sum of the block) and a "signed token" which the client can use as proof of knowledge for the block.
+# The client constructs a @manifest@ which lists the blocks by MD5 hash and how to reassemble them into the original files.
+# The client creates a "collection":{{site.baseurl}}/api/methods/collections.html and provides the @manifest_text@
+# The API server accepts the collection after validating the signed tokens (proof of knowledge) for each block.
+
+!{{site.baseurl}}/images/Keep_manifests.svg!
+
+h2. Fetching a file
+
+# The client requests a @collection@ object including @manifest_text@ from the APIs server
+# The server adds "token signatures" to the @manifest_text@ and returns it to the client.
+# The client discovers keep servers (or proxies) using the @accessible@ method on "keep_services":{{site.baseurl}}/api/methods/keep_services.html
+# For each data block, the client chooses the highest priority server using rendezvous hashing, described below.
+# The client sends the data block request to the keep server, along with the token signature from the API which proves to Keep servers that the client is permitted to read a given block.
+# The server provides the block data after validating the token signature for the block (if the server does not have the block, it returns a 404 and the client tries the next highest priority server)
+
+!{{site.baseurl}}/images/Keep_rendezvous_hashing.svg!
+
+Each @keep_service@ resource has an assigned uuid. To determine priority assignments of blocks to servers, for each keep service compute the MD5 sum of the string concatenation of the block locator (hex-coded hash part only) and service uuid, then sort this list in descending order. Blocks are preferentially placed on servers with the highest weight.
+
+h2. Keep server API
+
+The Keep server is accessed via a simple HTTP REST API.
+
+*GET /blocklocator+size+A@token*
+
+Fetch the data block. Response returns block contents. If permission checking is enabled, requires a valid token hint.
+
+*PUT /blocklocator*
+
+Body: the block contents. Responds the block locator consisting of MD5 sum of the data, block size, and signed token hint.
+
+*POST /*
+
+Body: the block contents. Responds the block locator consisting of MD5 sum of the data, block size, and signed token hint.
+
+h2(#locator). Keep locator format
+
+BNF notation for a valid Keep locator string (with hints). For example @d41d8cd98f00b204e9800998ecf8427e+0+Z+Ada39a3ee5e6b4b0d3255bfef95601890afd80709@53bed294@
+
+<pre>
+locator ::= sized-digest hint*
+sized-digest ::= digest size-hint
+digest ::= <32 lowercase hexadecimal digits>
+size-hint ::= "+" [0-9]+
+hint ::= "+" hint-type hint-content
+hint-type ::= [A-Z]+
+hint-content ::= [A-Za-z0-9@_-]*
+sign-hint ::= "+A" <40 lowercase hexadecimal digits> "@" sign-timestamp
+sign-timestamp ::= <8 lowercase hexadecimal digits>
+</pre>
+
+h3. Token signatures
+
+A token signature (sign-hint) provides proof-of-access for a data block. It is computed by taking a SHA1 HMAC of the blob signing token (a shared secret between the API server and keep servers), block digest, current API token, expiration timestamp, and blob signature TTL.
+
+When communicating with the Keep store to fetch a block, or the API server to create or update a collection, the service computes the expected token signature for each block and compares it to the token signature that was presented by the client. Keep clients receive valid block signatures when uploading a block to a keep store (getting back a signed token as proof of knowledge) or, from the API server, getting the manifest text of a collection on which the user has read permission.
+
+Security of a token signature is derived from the following characteristics:
+
+# Valid signatures can only be generated by entities that know the shared secret (the "blob signing token")
+# A signature can only be used by an entity that also know the API token that was used to generate it.
+# It expires after a set date (the expiration time, based on the "blob signature time-to-live (TTL)")
+
+h3. Regular expression to validate locator
+
+<pre>
+/^([0-9a-f]{32})\+([0-9]+)(\+[A-Z][-A-Za-z0-9@_]*)*$/
+</pre>
+
+h3. Valid locators
+
+table(table table-bordered table-condensed).
+|@d41d8cd98f00b204e9800998ecf8427e+0@|
+|@d41d8cd98f00b204e9800998ecf8427e+0+Z@|
+|<code>d41d8cd98f00b204e9800998ecf8427e+0+Z+Ada39a3ee5e6b4b0d3255bfef95601890afd80709@53bed294</code>|
+
+h3. Invalid locators
+
+table(table table-bordered table-condensed).
+||Why|
+|@d41d8cd98f00b204e9800998ecf8427e@|No size hint|
+|@d41d8cd98f00b204e9800998ecf8427e+Z+0@|Other hint before size hint|
+|@d41d8cd98f00b204e9800998ecf8427e+0+0@|Multiple size hints|
+|@d41d8cd98f00b204e9800998ecf8427e+0+z@|Hint does not start with uppercase letter|
+|@d41d8cd98f00b204e9800998ecf8427e+0+Zfoo*bar@|Hint contains invalid character @*@|
+
+h2. Manifest v1
+
+A manifest is utf-8 encoded text, consisting of zero or more newline-terminated streams.
+
+<pre>
+manifest ::= stream*
+stream ::= stream-name (" " locator)+ (" " file-segment)+ "\n"
+stream-name ::= "." ("/" path-component)*
+path-component ::= <printable ASCII - (whitespace, "/")>+
+file-segment ::= position ":" size ":" filename
+position ::= [0-9]+
+size ::= [0-9]+
+filename ::= path-component ("/" path-component)*
+</pre>
+
+Notes:
+
+* The first token is the stream name, consisting of one or more path components, delimited by @"/"@.
+** The first path component is always @"."@.
+** No path component is empty.
+** No path component following the first one can be "." or "..".
+** The stream name never begins or ends with @"/"@.
+* The next N tokens are "keep locators":#locator
+** These describe the "data stream". By logically concatenating the blocks in the order that they appear, we can refer to "positions" in the data stream.
+* File tokens come after the sequence of keep locators.
+** A file token has three parts, delimited by @":"@: position, size, filename.
+** Position and size are given in decimal
+** The position is the position in the data stream
+** The size is the count of bytes following the position in the data stream. A file size may cross multiple blocks in the data stream.
+** Filename may contain @"/"@ characters, but must not start or end with @"/"@, and must not contain @"//"@.
+** Filename components (delimited by @"/"@) must not be @"."@ or @".."@.
+** There may be multiple file tokens.
+
+It is legal to have multiple file tokens in the manifest (possible across different streams) with the same combined path name @stream name + "/" + filename@. This must be interpreted as a concatenation of file content, in the order that the file tokens appear in the manifest.
+
+Spaces are represented by the escape sequence @\040@. Spaces in stream names and filenames must be translated when reading and writing manifests. A manifest may not contain TAB characters, nor other ASCII whitespace characters or control codes other than the spaces or newlines used as delimiters specified above. A manifest always ends with a newline -- except the empty (zero-length) string, which is a valid manifest.
+
+h3. Normalized manifest v1
+
+A normalized manifest is a manifest that meets the following additional restrictions:
+
+* Streams are in alphanumeric order.
+* Each stream name is unique within the manifest.
+* Files within a stream are listed in alphanumeric order.
+* Blocks within a stream are ordered based on order of file tokens of the stream. A given block is listed at most once in a stream.
+* Filename must not contain @"/"@ (the stream name represents the path prefix)
+
+h3. Example manifests
+
+A manifest with four files in two directories:
+
+<pre>
+. 930625b054ce894ac40596c3f5a0d947+33 0:0:a 0:0:b 0:33:output.txt
+./c d41d8cd98f00b204e9800998ecf8427e+0 0:0:d
+</pre>
+
+The same manifest with permission signatures on each block:
+
+<pre>
+. 930625b054ce894ac40596c3f5a0d947+33+A1f27a35dd9af37191d63ad8eb8985624451e7b79@5835c8bc 0:0:a 0:0:b 0:33:output.txt
+./c d41d8cd98f00b204e9800998ecf8427e+0+A27117dcd30c013a6e85d6d74c9a50179a1446efa@5835c8bc 0:0:d
+</pre>
+
+A manifest containing a file consisting of multiple blocks and a space in the file name:
+
+<pre>
+. c449ed86671e4a34a8b8b9430850beba+67108864 09fcfea01c3a141b89dd0dcfa1b7768e+22534144 0:89643008:Docker\040image.tar
+</pre>
--- /dev/null
+---
+layout: default
+navsection: api
+title: API Authorization
+...
+
+All requests to the API server must have an API token. API tokens can be issued by going though the login flow, or created via the API. At this time, only browser based applications can perform login from email/password. Command line applications and services must use an API token provided via the @ARVADOS_API_TOKEN@ environment variable or configuration file.
+
+h2. Browser login
+
+Browser based applications can perform log in via the following highlevel flow:
+
+# The web application presents a "login" link to @/login@ on the API server with a @return_to@ parameter provided in the query portion of the URL. For example @https://{{ site.arvados_api_host }}/login?return_to=XXX@ , where @return_to=XXX@ is the URL of the login page for the web application.
+# The "login" link takes the browser to the login page (this may involve several redirects)
+# The user logs in. API server authenticates the user and issues a new API token.
+# The browser is redirected to the login page URL provided in @return_to=XXX@ with the addition of @?api_token=xxxxapitokenxxxx@.
+# The web application gets the login request with the included authorization token.
+
+!{{site.baseurl}}/images/Session_Establishment.svg!
+
+The "browser authentication process is documented in detail on the Arvados wiki.":https://dev.arvados.org/projects/arvados/wiki/Workbench_authentication_process
+
+h2. Creating tokens via the API
+
+The browser login method above issues a new token. Using that token, it is possible to make API calls to create additional tokens. To do so, use the @create@ method of the "API client authorizations":{{site.baseurl}}/api/methods/api_client_authorizations.html resource.
+
+h2. Trusted API clients
+
+The "api_clients":{{site.baseurl}}/api/methods/api_clients.html resource determines if web applications that have gone through the browser login flow may create or list API tokens.
+
+After the user has authenticated, but before an authorization token is issued and browser redirect sent (sending the browser back to the @return_to@ login page bearing @api_token@), the server strips the path and query portion from @return_to@ to get @url_prefix@. The @url_prefix@ is used to find or create an ApiClient object. The newly issued API client authorization (API token) is associated with this ApiClient object.
+
+API clients may be marked as "trusted" by making an API call to create or update an "api_clients":{{site.baseurl}}/api/methods/api_clients.html resource and set the @is_trusted@ flag to @true@. An authorization token associated with a "trusted" client is permitted to list authorization tokens on "API client authorizations":{{site.baseurl}}/api/methods/api_client_authorizations.html .
+
+A authorization token which is not associated with a trusted client may only use the @current@ method to query its own api_client_authorization object. The "untrusted" token is forbidden performing any other operations on API client authorizations, such as listing other authorizations or creating new authorizations.
+
+Authorization tokens which are not issued via the browser login flow (created directly via the API) will not have an associated api client. This means authorization tokens created via the API are always "untrusted".
+
+h2(#scopes). Scopes
+
+Scopes can restrict a token so it may only access certain resources. This is in addition to normal permission checks for the user associated with the token.
+
+Each entry in scopes consists of a @request_method@ and @request_path@, where the @request_method@ is a HTTP method (one of @GET@, @POST@, @PUT@ or @DELETE@) and @request_path@ is the request URI. A given request is permitted if it matches a scopes exactly, or the scope ends with @/@ and the request string is a prefix of the scope.
+
+As a special case, a scope of ["all"] allows all resources.
+
+h3. Scope examples
+
+A scope of @GET /arvados/v1/collections@ permits listing collections.
+
+* Requests with different methods, such as creating a new collection using @POST /arvados/v1/collections@, will be rejected.
+* Requests to access other resources, such as @GET /arvados/v1/groups@, will be rejected.
+* Be aware that requests for specific records, such as @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will also be rejected. This is because the scope @GET /arvados/v1/collections@ does not end in @/@
+
+A scope of @GET /arvados/v1/collections/@ (with @/@ suffix) will permit access to individual collections.
+
+* The request @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will succeed
+* Be aware that requests for listing @GET /arvados/v1/collections@ (no @/@ suffix) will be rejected, because it is not a match with the rule @GET /arvados/v1/collections/@
+* A listing request @GET /arvados/v1/collections/@ will have the trailing @/@ suffix trimmed before the scope check, as a result it will not match the rule @GET /arvados/v1/collections/@.
+
+To allow both listing objects and requesting individual objects, include both in the scope: @["GET /arvados/v1/collections", "GET /arvados/v1/collections/"]@
+
+A narrow scope such as @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will disallow listing objects as well as disallow requesting any object other than those listed in the scope.
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 1381.4540682414697 465.73490813648294" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="p.0"><path d="m0 0l1381.4541 0l0 465.7349l-1381.4541 0l0 -465.7349z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l1381.4541 0l0 465.7349l-1381.4541 0z" fill-rule="nonzero"></path><path fill="#76a5af" d="m167.81102 247.17343l0 0c0 -5.809967 4.709915 -10.519882 10.519897 -10.519882l116.660995 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728546 3.0812073 4.648636 3.0812073 7.438675l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099823 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m167.81102 247.17343l0 0c0 -5.809967 4.709915 -10.519882 10.519897 -10.519882l116.660995 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728546 3.0812073 4.648636 3.0812073 7.438675l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099823 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m226.62677 275.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm15.802948 11.296875l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5269" d="m322.10236 83.18898l0 0c0 -19.803978 25.586761 -35.858273 57.149628 -35.858273l0 0c31.562836 0 57.149597 16.054295 57.149597 35.858273l0 0c0 19.80397 -25.586761 35.85826 -57.149597 35.85826l0 0c-31.562866 0 -57.149628 -16.05429 -57.149628 -35.85826z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m322.10236 83.18898l0 0c0 -19.803978 25.586761 -35.858273 57.149628 -35.858273l0 0c31.562836 0 57.149597 16.054295 57.149597 35.858273l0 0c0 19.80397 -25.586761 35.85826 -57.149597 35.85826l0 0c-31.562866 0 -57.149628 -16.05429 -57.149628 -35.85826z" fill-rule="nonzero"></path><path fill="#000000" d="m368.687 76.51523l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.59793 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5255" d="m730.10236 115.18898l0 0c0 -15.385696 20.7359 -27.858269 46.31494 -27.858269l0 0c25.579102 0 46.315002 12.472572 46.315002 27.858269l0 0c0 15.385696 -20.7359 27.858261 -46.315002 27.858261l0 0c-25.57904 0 -46.31494 -12.472565 -46.31494 -27.858261z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m730.10236 115.18898l0 0c0 -15.385696 20.7359 -27.858269 46.31494 -27.858269l0 0c25.579102 0 46.315002 12.472572 46.315002 27.858269l0 0c0 15.385696 -20.7359 27.858261 -46.315002 27.858261l0 0c-25.57904 0 -46.31494 -12.472565 -46.31494 -27.858261z" fill-rule="nonzero"></path><path fill="#000000" d="m765.85236 108.51522l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.722961 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5255" d="m738.10236 319.28348l0 0c0 -13.22876 17.880432 -23.952759 39.93701 -23.952759l0 0c22.05658 0 39.93701 10.723999 39.93701 23.952759l0 0c0 13.228729 -17.880432 23.952728 -39.93701 23.952728l0 0c-22.05658 0 -39.93701 -10.723999 -39.93701 -23.952728z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m738.10236 319.28348l0 0c0 -13.22876 17.880432 -23.952759 39.93701 -23.952759l0 0c22.05658 0 39.93701 10.723999 39.93701 23.952759l0 0c0 13.228729 -17.880432 23.952728 -39.93701 23.952728l0 0c-22.05658 0 -39.93701 -10.723999 -39.93701 -23.952728z" fill-rule="nonzero"></path><path fill="#000000" d="m767.4744 312.6097l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm12.832336 9.984375l2.515625 -0.3125q0.125 0.96875 0.65625 1.484375q0.53125 0.5 1.28125 0.5q0.796875 0 1.34375 -0.609375q0.5625 -0.609375 0.5625 -1.640625q0 -0.984375 -0.53125 -1.5625q-0.53125 -0.578125 -1.28125 -0.578125q-0.5 0 -1.203125 0.203125l0.28125 -2.125q1.0625 0.015625 1.609375 -0.46875q0.5625 -0.484375 0.5625 -1.296875q0 -0.6875 -0.40625 -1.09375q-0.40625 -0.40625 -1.078125 -0.40625q-0.671875 0 -1.140625 0.46875q-0.46875 0.46875 -0.578125 1.359375l-2.40625 -0.421875q0.25 -1.234375 0.75 -1.96875q0.515625 -0.734375 1.421875 -1.15625q0.90625 -0.421875 2.03125 -0.421875q1.90625 0 3.078125 1.21875q0.953125 1.0 0.953125 2.265625q0 1.796875 -1.953125 2.859375q1.15625 0.25 1.859375 1.125q0.703125 0.875 0.703125 2.109375q0 1.78125 -1.3125 3.046875q-1.296875 1.265625 -3.25 1.265625q-1.84375 0 -3.0625 -1.0625q-1.21875 -1.0625 -1.40625 -2.78125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m379.25198 119.04724l-142.58269 117.60631" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m379.25198 119.04724l-137.95406 113.78847" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m240.24692 231.56151l-2.4498596 4.1618195l4.5518646 -1.6134033z" fill-rule="evenodd"></path><path fill="#76a5af" d="m55.811024 383.17343l0 0c0 -5.809967 4.709919 -10.519897 10.519894 -10.519897l116.660995 0c2.7900543 0 5.4658356 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.709915 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099747 0 -10.519894 -4.7099304 -10.519894 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m55.811024 383.17343l0 0c0 -5.809967 4.709919 -10.519897 10.519894 -10.519897l116.660995 0c2.7900543 0 5.4658356 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.709915 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099747 0 -10.519894 -4.7099304 -10.519894 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m114.62677 411.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm17.927948 8.875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#76a5af" d="m287.81104 383.17343l0 0c0 -5.809967 4.7099 -10.519897 10.519897 -10.519897l116.66098 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.66098 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m287.81104 383.17343l0 0c0 -5.809967 4.7099 -10.519897 10.519897 -10.519897l116.66098 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.66098 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m346.62677 411.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm9.037323 7.6875l2.515625 -0.3125q0.125 0.96875 0.65625 1.484375q0.53125 0.5 1.28125 0.5q0.796875 0 1.34375 -0.609375q0.5625 -0.609375 0.5625 -1.640625q0 -0.984375 -0.53125 -1.5625q-0.53125 -0.578125 -1.28125 -0.578125q-0.5 0 -1.203125 0.203125l0.28125 -2.125q1.0625 0.015625 1.609375 -0.46875q0.5625 -0.484375 0.5625 -1.296875q0 -0.6875 -0.40625 -1.09375q-0.40625 -0.40625 -1.078125 -0.40625q-0.671875 0 -1.140625 0.46875q-0.46875 0.46875 -0.578125 1.359375l-2.40625 -0.421875q0.25 -1.234375 0.75 -1.96875q0.515625 -0.734375 1.421875 -1.15625q0.90625 -0.421875 2.03125 -0.421875q1.90625 0 3.078125 1.21875q0.953125 1.0 0.953125 2.265625q0 1.796875 -1.953125 2.859375q1.15625 0.25 1.859375 1.125q0.703125 0.875 0.703125 2.109375q0 1.78125 -1.3125 3.046875q-1.296875 1.265625 -3.25 1.265625q-1.84375 0 -3.0625 -1.0625q-1.21875 -1.0625 -1.40625 -2.78125z" fill-rule="nonzero"></path><path fill="#76a5af" d="m447.81104 247.17343l0 0c0 -5.809967 4.7099 -10.519882 10.519897 -10.519882l116.66101 0c2.790039 0 5.4658203 1.1083374 7.4386597 3.0812073c1.9728394 1.9728546 3.0812378 4.648636 3.0812378 7.438675l0 42.07834c0 5.809967 -4.709961 10.519897 -10.519897 10.519897l-116.66101 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m447.81104 247.17343l0 0c0 -5.809967 4.7099 -10.519882 10.519897 -10.519882l116.66101 0c2.790039 0 5.4658203 1.1083374 7.4386597 3.0812073c1.9728394 1.9728546 3.0812378 4.648636 3.0812378 7.438675l0 42.07834c0 5.809967 -4.709961 10.519897 -10.519897 10.519897l-116.66101 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m506.62677 275.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm14.2404175 11.296875l0 -2.734375l-5.5625 0l0 -2.28125l5.890625 -8.640625l2.1875 0l0 8.625l1.6875 0l0 2.296875l-1.6875 0l0 2.734375l-2.515625 0zm0 -5.03125l0 -4.640625l-3.125 4.640625l3.125 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m730.10236 115.18898l-422.96063 128.06299" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m730.10236 115.18898l-417.21808 126.324265" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m312.40564 239.93239l-3.864746 2.895935l4.8220215 0.26579285z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m738.10236 319.28348l-152.59839 -51.08664" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m738.10236 319.28348l-146.90881 -49.181885" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m591.7179 268.5353l-4.8276978 0.12564087l3.7789917 3.006958z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m379.25198 119.04724l137.41733 117.60631" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m379.25198 119.04724l132.85886 113.70499" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m511.0368 234.00714l4.5217896 1.6958466l-2.3737793 -4.2056427z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m236.66142 299.77167l-112.00001 72.88187" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m236.66142 299.77167l-106.97102 69.609375" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m128.7895 367.9966l-2.902771 3.8595886l4.704544 -1.0907593z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m236.66142 299.77167l119.999985 72.88187" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m236.66142 299.77167l114.87175 69.76724" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m350.67575 370.95065l4.7361755 0.94400024l-3.0213318 -3.767517z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m500.65353 107.34646l142.58267 0l0 47.90551l-142.58267 0z" fill-rule="nonzero"></path><path fill="#000000" d="m512.21606 122.95396l0 1.9375l-1.7969055 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40628052 0.640625q-0.5000305 0.21875 -0.7500305 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.8750305 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4626465 7.7031174l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.5937424 0.515625 -2.7812424q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.8593674q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34374237 0 -0.43749237q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.2343674q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859367l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.6249924l0 6.0625l-1.671875 0l0 -6.0q0 -1.0156174 -0.203125 -1.5156174q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.5781174l0 5.375l-1.671875 0zm8.844482 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm13.735046 -3.78125l-3.015625 -9.859367l1.71875 0l1.5625 5.6874924l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.7812424l1.71875 0l1.46875 5.7187424l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.7031174l1.625 0l-3.078125 9.859367l-1.734375 0l-1.578125 -5.90625l-0.375 -1.6718674l-2.0 7.5781174l-1.734375 0zm11.629211 0l0 -9.859367l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.8906174 -0.28125 1.9531174l0 5.15625l-1.671875 0zm6.2439575 -11.687492l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.687492l0 -9.859367l1.671875 0l0 9.859367l-1.671875 0zm7.7854004 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.6562424l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.7499924q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm8.2771 -1.671875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.4843674 1.265625 -3.8593674q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.7968674q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.2343674 -0.625 -1.8593674q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.0468674zm8.672546 -5.9218674l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m643.4173 256.7638l120.0 0l0 41.95273l-120.0 0z" fill-rule="nonzero"></path><path fill="#000000" d="m654.9798 272.37128l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.891357 -3.78125l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9783325 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547546 4.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469482 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.828857 -6.875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m559.7454 366.88452l114.299194 0l0 51.08661l-114.299194 0z" fill-rule="nonzero"></path><path fill="#000000" d="m571.3079 382.492l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4626465 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844482 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.891296 -3.78125l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9783325 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547607 4.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469421 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.828857 -6.875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m302.40683 310.40683l152.59842 0l0 41.95276l-152.59842 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m321.48495 332.3268l2.671875 0.84375q-0.609375 2.21875 -2.046875 3.3125q-1.421875 1.078125 -3.609375 1.078125q-2.703125 0 -4.453125 -1.84375q-1.734375 -1.859375 -1.734375 -5.078125q0 -3.390625 1.75 -5.265625q1.75 -1.875 4.609375 -1.875q2.5 0 4.046875 1.46875q0.9375 0.875 1.390625 2.5l-2.71875 0.65625q-0.234375 -1.0625 -1.0 -1.671875q-0.765625 -0.609375 -1.859375 -0.609375q-1.515625 0 -2.453125 1.09375q-0.9375 1.078125 -0.9375 3.5q0 2.578125 0.921875 3.6875q0.921875 1.09375 2.40625 1.09375q1.109375 0 1.890625 -0.6875q0.78125 -0.703125 1.125 -2.203125zm7.254181 5.0l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463409 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm6.469452 -1.078125l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm9.453857 -5.125l0 2.078125l-1.78125 0l0 3.984375q0 1.203125 0.046875 1.40625q0.0625 0.1875 0.234375 0.328125q0.1875 0.125 0.453125 0.125q0.359375 0 1.046875 -0.25l0.21875 2.015625q-0.90625 0.390625 -2.0625 0.390625q-0.703125 0 -1.265625 -0.234375q-0.5625 -0.234375 -0.828125 -0.609375q-0.265625 -0.375 -0.375 -1.015625q-0.078125 -0.453125 -0.078125 -1.84375l0 -4.296875l-1.203125 0l0 -2.078125l1.203125 0l0 -1.953125l2.609375 -1.515625l0 3.46875l1.78125 0zm7.400177 6.71875l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563202 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.72293 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m546.8373 393.3071l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m556.5248 415.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.7229 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m514.8373 81.30708l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m524.5248 103.80521l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.5979 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m882.69293 27.729658l444.2834 0l0 407.5276l-444.2834 0z" fill-rule="nonzero"></path><path stroke="#c27ba0" stroke-width="2.0" stroke-linejoin="round" stroke-linecap="butt" d="m882.69293 27.729658l444.2834 0l0 407.5276l-444.2834 0z" fill-rule="nonzero"></path><path fill="#000000" d="m893.06793 54.64966l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm15.3810425 8.15625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm7.0163574 5.765625l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm4.572754 -9.859375l2.40625 0l0 1.359375q1.28125 -1.578125 3.0625 -1.578125q0.953125 0 1.640625 0.390625q0.703125 0.390625 1.140625 1.1875q0.65625 -0.796875 1.40625 -1.1875q0.75 -0.390625 1.609375 -0.390625q1.078125 0 1.828125 0.453125q0.75 0.4375 1.125 1.28125q0.265625 0.640625 0.265625 2.046875l0 6.296875l-2.609375 0l0 -5.625q0 -1.46875 -0.265625 -1.90625q-0.359375 -0.546875 -1.109375 -0.546875q-0.546875 0 -1.03125 0.34375q-0.484375 0.328125 -0.703125 0.96875q-0.203125 0.640625 -0.203125 2.03125l0 4.734375l-2.609375 0l0 -5.40625q0 -1.4375 -0.140625 -1.84375q-0.140625 -0.421875 -0.4375 -0.625q-0.28125 -0.203125 -0.78125 -0.203125q-0.609375 0 -1.09375 0.328125q-0.484375 0.3125 -0.6875 0.9375q-0.203125 0.609375 -0.203125 2.03125l0 4.78125l-2.609375 0l0 -9.859375zm16.775879 -1.328125l0 -2.40625l2.609375 0l0 2.40625l-2.609375 0zm0 11.1875l0 -9.859375l2.609375 0l0 9.859375l-2.609375 0zm4.2770996 -2.8125l2.609375 -0.390625q0.171875 0.75 0.671875 1.15625q0.515625 0.390625 1.4375 0.390625q1.0 0 1.515625 -0.375q0.34375 -0.265625 0.34375 -0.703125q0 -0.296875 -0.1875 -0.484375q-0.1875 -0.1875 -0.875 -0.34375q-3.140625 -0.703125 -4.0 -1.265625q-1.15625 -0.796875 -1.15625 -2.21875q0 -1.28125 1.0 -2.15625q1.015625 -0.875 3.140625 -0.875q2.03125 0 3.0 0.65625q0.984375 0.65625 1.359375 1.953125l-2.453125 0.453125q-0.15625 -0.578125 -0.609375 -0.875q-0.4375 -0.3125 -1.25 -0.3125q-1.03125 0 -1.46875 0.296875q-0.296875 0.203125 -0.296875 0.515625q0 0.28125 0.25 0.484375q0.359375 0.25 2.4375 0.734375q2.078125 0.46875 2.90625 1.15625q0.828125 0.6875 0.828125 1.9375q0 1.359375 -1.140625 2.328125q-1.125 0.96875 -3.34375 0.96875q-2.015625 0 -3.1875 -0.8125q-1.171875 -0.8125 -1.53125 -2.21875zm10.375671 0l2.609375 -0.390625q0.171875 0.75 0.671875 1.15625q0.515625 0.390625 1.4375 0.390625q1.0 0 1.515625 -0.375q0.34375 -0.265625 0.34375 -0.703125q0 -0.296875 -0.1875 -0.484375q-0.1875 -0.1875 -0.875 -0.34375q-3.140625 -0.703125 -4.0 -1.265625q-1.15625 -0.796875 -1.15625 -2.21875q0 -1.28125 1.0 -2.15625q1.015625 -0.875 3.140625 -0.875q2.03125 0 3.0 0.65625q0.984375 0.65625 1.359375 1.953125l-2.453125 0.453125q-0.15625 -0.578125 -0.609375 -0.875q-0.4375 -0.3125 -1.25 -0.3125q-1.03125 0 -1.46875 0.296875q-0.296875 0.203125 -0.296875 0.515625q0 0.28125 0.25 0.484375q0.359375 0.25 2.4375 0.734375q2.078125 0.46875 2.90625 1.15625q0.828125 0.6875 0.828125 1.9375q0 1.359375 -1.140625 2.328125q-1.125 0.96875 -3.34375 0.96875q-2.015625 0 -3.1875 -0.8125q-1.171875 -0.8125 -1.53125 -2.21875zm11.281982 -8.375l0 -2.40625l2.609375 0l0 2.40625l-2.609375 0zm0 11.1875l0 -9.859375l2.609375 0l0 9.859375l-2.609375 0zm4.5895386 -5.0625q0 -1.296875 0.640625 -2.515625q0.640625 -1.21875 1.8125 -1.859375q1.171875 -0.640625 2.609375 -0.640625q2.25 0 3.671875 1.453125q1.421875 1.453125 1.421875 3.671875q0 2.234375 -1.4375 3.703125q-1.4375 1.46875 -3.625 1.46875q-1.359375 0 -2.59375 -0.609375q-1.21875 -0.609375 -1.859375 -1.796875q-0.640625 -1.1875 -0.640625 -2.875zm2.671875 0.140625q0 1.46875 0.6875 2.25q0.703125 0.765625 1.71875 0.765625q1.015625 0 1.703125 -0.765625q0.703125 -0.78125 0.703125 -2.265625q0 -1.453125 -0.703125 -2.234375q-0.6875 -0.78125 -1.703125 -0.78125q-1.015625 0 -1.71875 0.78125q-0.6875 0.78125 -0.6875 2.25zm18.286621 4.921875l-2.609375 0l0 -5.03125q0 -1.59375 -0.171875 -2.0625q-0.15625 -0.46875 -0.53125 -0.71875q-0.375 -0.265625 -0.90625 -0.265625q-0.6875 0 -1.234375 0.375q-0.53125 0.359375 -0.734375 0.984375q-0.1875 0.609375 -0.1875 2.25l0 4.46875l-2.609375 0l0 -9.859375l2.421875 0l0 1.453125q1.296875 -1.671875 3.25 -1.671875q0.859375 0 1.578125 0.3125q0.71875 0.3125 1.078125 0.796875q0.359375 0.484375 0.5 1.09375q0.15625 0.609375 0.15625 1.75l0 6.125zm1.5209961 -2.8125l2.609375 -0.390625q0.171875 0.75 0.671875 1.15625q0.515625 0.390625 1.4375 0.390625q1.0 0 1.515625 -0.375q0.34375 -0.265625 0.34375 -0.703125q0 -0.296875 -0.1875 -0.484375q-0.1875 -0.1875 -0.875 -0.34375q-3.140625 -0.703125 -4.0 -1.265625q-1.15625 -0.796875 -1.15625 -2.21875q0 -1.28125 1.0 -2.15625q1.015625 -0.875 3.140625 -0.875q2.03125 0 3.0 0.65625q0.984375 0.65625 1.359375 1.953125l-2.453125 0.453125q-0.15625 -0.578125 -0.609375 -0.875q-0.4375 -0.3125 -1.25 -0.3125q-1.03125 0 -1.46875 0.296875q-0.296875 0.203125 -0.296875 0.515625q0 0.28125 0.25 0.484375q0.359375 0.25 2.4375 0.734375q2.078125 0.46875 2.90625 1.15625q0.828125 0.6875 0.828125 1.9375q0 1.359375 -1.140625 2.328125q-1.125 0.96875 -3.34375 0.96875q-2.015625 0 -3.1875 -0.8125q-1.171875 -0.8125 -1.53125 -2.21875zm11.781982 -4.4375l0 -2.609375l2.609375 0l0 2.609375l-2.609375 0zm0 7.25l0 -2.609375l2.609375 0l0 2.609375l-2.609375 0z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 85.05591l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm10.1604 13.59375l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm9.090271 -4.078125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm16.256104 7.140625l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm4.9850464 0l0 -1.90625l1.90625 0l0 1.90625q0 1.046875 -0.375 1.6875q-0.375 0.65625 -1.171875 1.0l-0.46875 -0.71875q0.53125 -0.21875 0.78125 -0.671875q0.25 -0.453125 0.28125 -1.296875l-0.953125 0zm10.147888 0l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm18.740417 5.53125l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm2.5007324 1.609375l0 -1.90625l1.90625 0l0 1.90625q0 1.046875 -0.375 1.6875q-0.375 0.65625 -1.171875 1.0l-0.46875 -0.71875q0.53125 -0.21875 0.78125 -0.671875q0.25 -0.453125 0.28125 -1.296875l-0.953125 0zm10.147888 0l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm9.9747925 3.546875l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm11.266357 3.59375l0 -1.90625l1.906189 0l0 1.90625q0 1.046875 -0.375 1.6875q-0.375 0.65625 -1.171814 1.0l-0.46875 -0.71875q0.53125 -0.21875 0.78125 -0.671875q0.25 -0.453125 0.28125 -1.296875l-0.953125 0zm10.147888 0l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm15.318481 7.140625l0 -3.25l-5.90625 0l0 -1.53125l6.21875 -8.8125l1.359375 0l0 8.8125l1.84375 0l0 1.53125l-1.84375 0l0 3.25l-1.671875 0zm0 -4.78125l0 -6.140625l-4.25 6.140625l4.25 0zm10.027832 0.703125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.349121 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4626465 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844482 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.906982 -3.78125l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978271 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819824 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047607 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.672607 -5.921875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145996 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.4001465 -8.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm11.110107 4.921875l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.644775 0l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm17.125732 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm7.3221436 4.0l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 129.05591l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm12.644775 11.984375l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm16.256104 7.140625l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm9.090271 -4.078125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.34906 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm13.735107 -3.78125l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.62915 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2440186 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7854004 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm8.2771 -1.671875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.672607 -5.921875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145874 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.3533936 -6.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 2.9375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0631104 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.978394 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm15.99646 4.921875l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.766357 8.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm23.730103 -17.390625l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm10.160522 13.59375l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm5.6413574 4.0l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 173.05591l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm12.644775 11.984375l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm18.740479 5.53125l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.34906 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.906982 -3.78125l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978271 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819824 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047607 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.672607 -5.921875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145996 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.3532715 -6.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 2.9375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm15.99646 4.921875l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.766357 8.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm23.730225 -17.390625l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm10.1604 13.59375l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm9.090332 -4.078125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm11.739746 4.890625l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm9.281982 5.109375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.6657715 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm14.031982 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.85510254 -1.4375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375z" fill-rule="nonzero"></path><path fill="#000000" d="m892.94293 212.43091l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.610046 1.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2283325 0l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm15.5563965 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.4573364 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.328125 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.015625 -8.75l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.5042114 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281921 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm19.215271 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020996 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm13.793396 1.984375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 2.9375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm13.668335 0.953125q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm12.938232 3.421875l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270996 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm17.125732 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.5563965 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm14.511353 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.453125 2.9375l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm10.360107 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.890625 3.609375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm21.996582 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.4069824 2.0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm24.323853 -10.65625l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm3.8792725 10.0l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm11.922607 7.59375l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 239.05591l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm12.644775 11.984375l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm9.9748535 3.546875l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm15.371521 -0.484375l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.34906 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm13.735107 -3.78125l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.62915 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2440186 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7854004 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm8.2771 -1.671875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.672607 -5.921875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145874 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm3.0408936 -15.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.1291504 0l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm10.375732 0l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm17.125732 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2438965 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7854004 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm8.2771 -1.671875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm14.855835 4.921875l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm4.7614746 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.6032715 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm20.942871 0l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm16.256104 7.140625l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm5.6412354 4.0l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 283.05588l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm12.644775 11.984375l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm15.3186035 7.140625l0 -3.25l-5.90625 0l0 -1.53125l6.21875 -8.8125l1.359375 0l0 8.8125l1.84375 0l0 1.53125l-1.84375 0l0 3.25l-1.671875 0zm0 -4.78125l0 -6.140625l-4.25 6.140625l4.25 0zm10.027771 0.703125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.03656 4.078125l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm9.750732 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm17.125732 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 327.05588l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm3.8791504 10.0l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm15.371521 -0.484375l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm16.256104 7.140625l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm4.9850464 0l0 -1.90625l1.90625 0l0 1.90625q0 1.046875 -0.375 1.6875q-0.375 0.65625 -1.171875 1.0l-0.46875 -0.71875q0.53125 -0.21875 0.78125 -0.671875q0.25 -0.453125 0.28125 -1.296875l-0.953125 0zm10.147888 0l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm9.9747925 3.546875l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm15.371521 -0.484375l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.036621 4.078125l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm9.750732 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm17.125732 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 371.05588l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm3.8791504 10.0l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm15.371521 -0.484375l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm18.740479 5.53125l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm6.605896 -2.46875l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.34906 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.891357 -3.78125l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547607 4.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469482 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.828857 -6.875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145996 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.3532715 -6.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 2.9375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm15.99646 4.921875l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.766357 8.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm23.730225 -17.390625l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm12.644775 11.984375l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm3.1569824 5.609375l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m902.08356 415.05588l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm3.8791504 10.0l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm15.371521 -0.484375l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm12.255371 4.078125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm15.3186035 7.140625l0 -3.25l-5.90625 0l0 -1.53125l6.21875 -8.8125l1.359375 0l0 8.8125l1.84375 0l0 1.53125l-1.84375 0l0 3.25l-1.671875 0zm0 -4.78125l0 -6.140625l-4.25 6.140625l4.25 0zm10.027771 0.703125l0 -1.6875l5.125 0l0 1.6875l-5.125 0zm13.34906 -7.234375l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4627075 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844421 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.891357 -3.78125l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547607 4.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469482 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.828857 -6.875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0zm12.145996 15.796875q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.3532715 -6.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 2.9375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm15.99646 4.921875l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.766357 8.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm23.730225 -17.390625l1.796875 0l0 7.84375q0 2.0625 -0.46875 3.265625q-0.453125 1.203125 -1.671875 1.96875q-1.203125 0.75 -3.171875 0.75q-1.90625 0 -3.125 -0.65625q-1.21875 -0.65625 -1.734375 -1.90625q-0.515625 -1.25 -0.515625 -3.421875l0 -7.84375l1.796875 0l0 7.84375q0 1.765625 0.328125 2.609375q0.328125 0.84375 1.125 1.296875q0.8125 0.453125 1.96875 0.453125q1.984375 0 2.828125 -0.890625q0.84375 -0.90625 0.84375 -3.46875l0 -7.84375zm10.1604 13.59375l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm5.6413574 4.0l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m748.18634 137.59842l-557.7638 242.01575" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m748.18634 137.59842l-552.2596 239.62747" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m195.26929 375.71063l-3.5056152 3.3216248l4.8205566 -0.2911377z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m634.56696 151.3307l152.59839 0l0 41.95276l-152.59839 0z" fill-rule="nonzero"></path><path fill="#000000" d="m646.12946 166.9382l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4626465 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844482 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.906921 -3.78125l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978333 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813171 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819824 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047607 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.672607 -5.921875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m602.8373 289.3071l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m612.5248 311.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.5979 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m618.8373 177.30708l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m628.5248 199.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.5979 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#76a5af" d="m167.81102 247.17343l0 0c0 -5.809967 4.709915 -10.519882 10.519897 -10.519882l116.660995 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728546 3.0812073 4.648636 3.0812073 7.438675l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099823 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m167.81102 247.17343l0 0c0 -5.809967 4.709915 -10.519882 10.519897 -10.519882l116.660995 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728546 3.0812073 4.648636 3.0812073 7.438675l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099823 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m226.62677 275.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm15.802948 11.296875l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5269" d="m322.10236 83.18898l0 0c0 -19.803978 25.586761 -35.858273 57.149628 -35.858273l0 0c31.562836 0 57.149597 16.054295 57.149597 35.858273l0 0c0 19.80397 -25.586761 35.85826 -57.149597 35.85826l0 0c-31.562866 0 -57.149628 -16.05429 -57.149628 -35.85826z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m322.10236 83.18898l0 0c0 -19.803978 25.586761 -35.858273 57.149628 -35.858273l0 0c31.562836 0 57.149597 16.054295 57.149597 35.858273l0 0c0 19.80397 -25.586761 35.85826 -57.149597 35.85826l0 0c-31.562866 0 -57.149628 -16.05429 -57.149628 -35.85826z" fill-rule="nonzero"></path><path fill="#000000" d="m368.687 76.51523l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.59793 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5255" d="m730.10236 115.18898l0 0c0 -15.385696 20.7359 -27.858269 46.31494 -27.858269l0 0c25.579102 0 46.315002 12.472572 46.315002 27.858269l0 0c0 15.385696 -20.7359 27.858261 -46.315002 27.858261l0 0c-25.57904 0 -46.31494 -12.472565 -46.31494 -27.858261z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m730.10236 115.18898l0 0c0 -15.385696 20.7359 -27.858269 46.31494 -27.858269l0 0c25.579102 0 46.315002 12.472572 46.315002 27.858269l0 0c0 15.385696 -20.7359 27.858261 -46.315002 27.858261l0 0c-25.57904 0 -46.31494 -12.472565 -46.31494 -27.858261z" fill-rule="nonzero"></path><path fill="#000000" d="m765.85236 108.51522l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.722961 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#f3a7eb" fill-opacity="0.5255" d="m738.10236 319.28348l0 0c0 -13.22876 17.880432 -23.952759 39.93701 -23.952759l0 0c22.05658 0 39.93701 10.723999 39.93701 23.952759l0 0c0 13.228729 -17.880432 23.952728 -39.93701 23.952728l0 0c-22.05658 0 -39.93701 -10.723999 -39.93701 -23.952728z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m738.10236 319.28348l0 0c0 -13.22876 17.880432 -23.952759 39.93701 -23.952759l0 0c22.05658 0 39.93701 10.723999 39.93701 23.952759l0 0c0 13.228729 -17.880432 23.952728 -39.93701 23.952728l0 0c-22.05658 0 -39.93701 -10.723999 -39.93701 -23.952728z" fill-rule="nonzero"></path><path fill="#000000" d="m767.4744 312.6097l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm12.832336 9.984375l2.515625 -0.3125q0.125 0.96875 0.65625 1.484375q0.53125 0.5 1.28125 0.5q0.796875 0 1.34375 -0.609375q0.5625 -0.609375 0.5625 -1.640625q0 -0.984375 -0.53125 -1.5625q-0.53125 -0.578125 -1.28125 -0.578125q-0.5 0 -1.203125 0.203125l0.28125 -2.125q1.0625 0.015625 1.609375 -0.46875q0.5625 -0.484375 0.5625 -1.296875q0 -0.6875 -0.40625 -1.09375q-0.40625 -0.40625 -1.078125 -0.40625q-0.671875 0 -1.140625 0.46875q-0.46875 0.46875 -0.578125 1.359375l-2.40625 -0.421875q0.25 -1.234375 0.75 -1.96875q0.515625 -0.734375 1.421875 -1.15625q0.90625 -0.421875 2.03125 -0.421875q1.90625 0 3.078125 1.21875q0.953125 1.0 0.953125 2.265625q0 1.796875 -1.953125 2.859375q1.15625 0.25 1.859375 1.125q0.703125 0.875 0.703125 2.109375q0 1.78125 -1.3125 3.046875q-1.296875 1.265625 -3.25 1.265625q-1.84375 0 -3.0625 -1.0625q-1.21875 -1.0625 -1.40625 -2.78125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m379.25198 119.04724l-142.58269 117.60631" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m379.25198 119.04724l-137.95406 113.78847" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m240.24692 231.56151l-2.4498596 4.1618195l4.5518646 -1.6134033z" fill-rule="evenodd"></path><path fill="#76a5af" d="m55.811024 383.17343l0 0c0 -5.809967 4.709919 -10.519897 10.519894 -10.519897l116.660995 0c2.7900543 0 5.4658356 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.709915 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099747 0 -10.519894 -4.7099304 -10.519894 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m55.811024 383.17343l0 0c0 -5.809967 4.709919 -10.519897 10.519894 -10.519897l116.660995 0c2.7900543 0 5.4658356 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.709915 10.519897 -10.519897 10.519897l-116.660995 0c-5.8099747 0 -10.519894 -4.7099304 -10.519894 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m114.62677 411.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm17.927948 8.875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#76a5af" d="m447.81104 247.17343l0 0c0 -5.809967 4.7099 -10.519882 10.519897 -10.519882l116.66101 0c2.790039 0 5.4658203 1.1083374 7.4386597 3.0812073c1.9728394 1.9728546 3.0812378 4.648636 3.0812378 7.438675l0 42.07834c0 5.809967 -4.709961 10.519897 -10.519897 10.519897l-116.66101 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m447.81104 247.17343l0 0c0 -5.809967 4.7099 -10.519882 10.519897 -10.519882l116.66101 0c2.790039 0 5.4658203 1.1083374 7.4386597 3.0812073c1.9728394 1.9728546 3.0812378 4.648636 3.0812378 7.438675l0 42.07834c0 5.809967 -4.709961 10.519897 -10.519897 10.519897l-116.66101 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m506.62677 275.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm14.2404175 11.296875l0 -2.734375l-5.5625 0l0 -2.28125l5.890625 -8.640625l2.1875 0l0 8.625l1.6875 0l0 2.296875l-1.6875 0l0 2.734375l-2.515625 0zm0 -5.03125l0 -4.640625l-3.125 4.640625l3.125 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m730.10236 115.18898l-422.96063 128.06299" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m730.10236 115.18898l-417.21808 126.324265" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m312.40564 239.93239l-3.864746 2.895935l4.8220215 0.26579285z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m738.10236 319.28348l-152.59839 -51.08664" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m738.10236 319.28348l-146.90881 -49.181885" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m591.7179 268.5353l-4.8276978 0.12564087l3.7789917 3.006958z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m379.25198 119.04724l137.41733 117.60631" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m379.25198 119.04724l132.85886 113.70499" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m511.0368 234.00714l4.5217896 1.6958466l-2.3737793 -4.2056427z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m236.66142 299.77167l-112.00001 72.88187" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m236.66142 299.77167l-106.97102 69.609375" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m128.7895 367.9966l-2.902771 3.8595886l4.704544 -1.0907593z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m236.66142 299.77167l119.999985 72.88187" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m236.66142 299.77167l114.87175 69.76724" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m350.67575 370.95065l4.7361755 0.94400024l-3.0213318 -3.767517z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m749.7996 336.2206l-556.28345 68.0" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" stroke-dasharray="4.0,3.0,1.0,3.0" d="m749.7996 336.2206l-550.32776 67.272" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m199.27144 401.8531l-4.3041534 2.190155l4.7049713 1.0888977z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m559.7454 366.88452l114.299194 0l0 51.08661l-114.299194 0z" fill-rule="nonzero"></path><path fill="#000000" d="m571.3079 382.492l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm2.875 0l0 1.9375l-1.796875 0l0 -1.53125q0 -1.25 0.296875 -1.796875q0.390625 -0.75 1.234375 -1.125l0.40625 0.640625q-0.5 0.21875 -0.75 0.640625q-0.234375 0.421875 -0.265625 1.234375l0.875 0zm8.4626465 7.703125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm8.844482 3.78125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.891296 -3.78125l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9783325 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547607 4.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469421 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.828857 -6.875l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.265625 -1.203125l-0.859375 0zm2.875 0l0 -1.9375l1.78125 0l0 1.53125q0 1.234375 -0.28125 1.78125q-0.40625 0.75 -1.25 1.140625l-0.40625 -0.671875q0.5 -0.203125 0.75 -0.640625q0.25 -0.4375 0.28125 -1.203125l-0.875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m302.40683 310.40683l152.59842 0l0 41.95276l-152.59842 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m321.48495 332.3268l2.671875 0.84375q-0.609375 2.21875 -2.046875 3.3125q-1.421875 1.078125 -3.609375 1.078125q-2.703125 0 -4.453125 -1.84375q-1.734375 -1.859375 -1.734375 -5.078125q0 -3.390625 1.75 -5.265625q1.75 -1.875 4.609375 -1.875q2.5 0 4.046875 1.46875q0.9375 0.875 1.390625 2.5l-2.71875 0.65625q-0.234375 -1.0625 -1.0 -1.671875q-0.765625 -0.609375 -1.859375 -0.609375q-1.515625 0 -2.453125 1.09375q-0.9375 1.078125 -0.9375 3.5q0 2.578125 0.921875 3.6875q0.921875 1.09375 2.40625 1.09375q1.109375 0 1.890625 -0.6875q0.78125 -0.703125 1.125 -2.203125zm7.254181 5.0l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463409 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm6.469452 -1.078125l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm9.453857 -5.125l0 2.078125l-1.78125 0l0 3.984375q0 1.203125 0.046875 1.40625q0.0625 0.1875 0.234375 0.328125q0.1875 0.125 0.453125 0.125q0.359375 0 1.046875 -0.25l0.21875 2.015625q-0.90625 0.390625 -2.0625 0.390625q-0.703125 0 -1.265625 -0.234375q-0.5625 -0.234375 -0.828125 -0.609375q-0.265625 -0.375 -0.375 -1.015625q-0.078125 -0.453125 -0.078125 -1.84375l0 -4.296875l-1.203125 0l0 -2.078125l1.203125 0l0 -1.953125l2.609375 -1.515625l0 3.46875l1.78125 0zm7.400177 6.71875l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563202 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.72293 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m546.8373 393.3071l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m556.5248 415.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm21.7229 11.171875l0 2.421875l-9.140625 0q0.15625 -1.375 0.890625 -2.59375q0.75 -1.234375 2.9375 -3.265625q1.765625 -1.640625 2.15625 -2.234375q0.546875 -0.796875 0.546875 -1.59375q0 -0.875 -0.46875 -1.34375q-0.46875 -0.46875 -1.296875 -0.46875q-0.8125 0 -1.296875 0.5q-0.484375 0.484375 -0.5625 1.625l-2.59375 -0.25q0.234375 -2.15625 1.453125 -3.09375q1.21875 -0.9375 3.0625 -0.9375q2.015625 0 3.15625 1.09375q1.15625 1.078125 1.15625 2.6875q0 0.921875 -0.328125 1.75q-0.328125 0.828125 -1.046875 1.734375q-0.46875 0.609375 -1.703125 1.75q-1.234375 1.125 -1.5625 1.5q-0.328125 0.359375 -0.53125 0.71875l5.171875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m602.8373 289.3071l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m612.5248 311.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.5979 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m618.8373 177.30708l142.58264 0l0 41.95276l-142.58264 0z" fill-rule="nonzero"></path><path fill="#a61c00" d="m628.5248 199.8052l2.671875 -0.265625q0.234375 1.34375 0.96875 1.984375q0.75 0.625 2.0 0.625q1.328125 0 2.0 -0.5625q0.671875 -0.5625 0.671875 -1.3125q0 -0.484375 -0.28125 -0.8125q-0.28125 -0.34375 -0.984375 -0.59375q-0.484375 -0.171875 -2.203125 -0.59375q-2.203125 -0.546875 -3.09375 -1.34375q-1.265625 -1.125 -1.265625 -2.734375q0 -1.046875 0.59375 -1.953125q0.59375 -0.90625 1.703125 -1.375q1.109375 -0.46875 2.671875 -0.46875q2.5625 0 3.859375 1.125q1.296875 1.109375 1.359375 2.984375l-2.75 0.125q-0.171875 -1.046875 -0.75 -1.5q-0.578125 -0.46875 -1.75 -0.46875q-1.1875 0 -1.875 0.5q-0.4375 0.3125 -0.4375 0.84375q0 0.484375 0.421875 0.828125q0.515625 0.421875 2.515625 0.90625q2.0 0.46875 2.953125 0.984375q0.96875 0.5 1.515625 1.375q0.546875 0.875 0.546875 2.15625q0 1.171875 -0.65625 2.203125q-0.640625 1.015625 -1.828125 1.515625q-1.1875 0.484375 -2.96875 0.484375q-2.578125 0 -3.96875 -1.1875q-1.375 -1.1875 -1.640625 -3.46875zm15.7247925 -9.171875l0 5.0q1.25 -1.484375 3.015625 -1.484375q0.890625 0 1.609375 0.34375q0.734375 0.328125 1.09375 0.84375q0.375 0.515625 0.5 1.15625q0.140625 0.625 0.140625 1.953125l0 5.78125l-2.609375 0l0 -5.203125q0 -1.546875 -0.15625 -1.96875q-0.140625 -0.421875 -0.515625 -0.65625q-0.375 -0.25 -0.9375 -0.25q-0.65625 0 -1.171875 0.3125q-0.5 0.3125 -0.734375 0.953125q-0.234375 0.640625 -0.234375 1.875l0 4.9375l-2.609375 0l0 -13.59375l2.609375 0zm10.739746 6.75l-2.359375 -0.4375q0.390625 -1.421875 1.359375 -2.109375q0.984375 -0.6875 2.90625 -0.6875q1.734375 0 2.59375 0.421875q0.859375 0.40625 1.203125 1.046875q0.34375 0.625 0.34375 2.328125l-0.03125 3.046875q0 1.296875 0.125 1.921875q0.125 0.609375 0.46875 1.3125l-2.578125 0q-0.09375 -0.265625 -0.25 -0.765625q-0.0625 -0.234375 -0.09375 -0.3125q-0.65625 0.65625 -1.421875 0.984375q-0.765625 0.3125 -1.625 0.3125q-1.515625 0 -2.40625 -0.8125q-0.875 -0.828125 -0.875 -2.09375q0 -0.84375 0.390625 -1.484375q0.40625 -0.65625 1.125 -1.0q0.71875 -0.359375 2.078125 -0.625q1.828125 -0.328125 2.53125 -0.625l0 -0.265625q0 -0.75 -0.375 -1.0625q-0.359375 -0.328125 -1.390625 -0.328125q-0.703125 0 -1.09375 0.28125q-0.390625 0.265625 -0.625 0.953125zm3.484375 2.109375q-0.5 0.171875 -1.59375 0.40625q-1.078125 0.234375 -1.40625 0.453125q-0.515625 0.359375 -0.515625 0.921875q0 0.546875 0.40625 0.953125q0.40625 0.390625 1.046875 0.390625q0.703125 0 1.34375 -0.46875q0.46875 -0.359375 0.625 -0.859375q0.09375 -0.34375 0.09375 -1.28125l0 -0.515625zm7.4382324 4.734375l-2.609375 0l0 -9.859375l2.421875 0l0 1.40625q0.625 -0.984375 1.109375 -1.296875q0.5 -0.328125 1.140625 -0.328125q0.890625 0 1.71875 0.5l-0.8125 2.265625q-0.65625 -0.421875 -1.21875 -0.421875q-0.546875 0 -0.9375 0.296875q-0.375 0.296875 -0.59375 1.09375q-0.21875 0.78125 -0.21875 3.296875l0 3.046875zm10.463379 -3.140625l2.609375 0.4375q-0.5 1.4375 -1.59375 2.1875q-1.078125 0.734375 -2.703125 0.734375q-2.5625 0 -3.796875 -1.671875q-0.96875 -1.34375 -0.96875 -3.40625q0 -2.4375 1.265625 -3.828125q1.28125 -1.390625 3.25 -1.390625q2.1875 0 3.453125 1.453125q1.28125 1.453125 1.234375 4.453125l-6.53125 0q0.015625 1.15625 0.625 1.8125q0.609375 0.640625 1.5 0.640625q0.609375 0 1.03125 -0.328125q0.421875 -0.34375 0.625 -1.09375zm0.15625 -2.625q-0.03125 -1.140625 -0.59375 -1.71875q-0.546875 -0.59375 -1.34375 -0.59375q-0.859375 0 -1.40625 0.625q-0.5625 0.609375 -0.546875 1.6875l3.890625 0zm13.563232 5.765625l-2.421875 0l0 -1.453125q-0.609375 0.84375 -1.4375 1.265625q-0.8125 0.40625 -1.640625 0.40625q-1.703125 0 -2.921875 -1.359375q-1.203125 -1.375 -1.203125 -3.828125q0 -2.5 1.171875 -3.796875q1.1875 -1.3125 2.984375 -1.3125q1.65625 0 2.859375 1.375l0 -4.890625l2.609375 0l0 13.59375zm-6.96875 -5.140625q0 1.578125 0.4375 2.28125q0.640625 1.015625 1.765625 1.015625q0.90625 0 1.53125 -0.765625q0.625 -0.765625 0.625 -2.28125q0 -1.703125 -0.609375 -2.4375q-0.609375 -0.75 -1.5625 -0.75q-0.9375 0 -1.5625 0.734375q-0.625 0.734375 -0.625 2.203125zm14.391785 5.140625l0 -13.59375l2.609375 0l0 4.890625q1.203125 -1.375 2.859375 -1.375q1.796875 0 2.96875 1.3125q1.1875 1.296875 1.1875 3.734375q0 2.53125 -1.203125 3.890625q-1.203125 1.359375 -2.921875 1.359375q-0.84375 0 -1.671875 -0.421875q-0.8125 -0.421875 -1.40625 -1.25l0 1.453125l-2.421875 0zm2.59375 -5.140625q0 1.53125 0.484375 2.265625q0.671875 1.03125 1.796875 1.03125q0.859375 0 1.46875 -0.734375q0.609375 -0.734375 0.609375 -2.328125q0 -1.6875 -0.609375 -2.421875q-0.609375 -0.75 -1.578125 -0.75q-0.9375 0 -1.5625 0.734375q-0.609375 0.71875 -0.609375 2.203125zm7.677246 -4.71875l2.78125 0l2.359375 7.0l2.296875 -7.0l2.703125 0l-3.484375 9.484375l-0.625 1.71875q-0.34375 0.859375 -0.65625 1.3125q-0.296875 0.46875 -0.703125 0.75q-0.40625 0.28125 -1.0 0.4375q-0.59375 0.15625 -1.328125 0.15625q-0.75 0 -1.46875 -0.15625l-0.234375 -2.046875q0.609375 0.125 1.09375 0.125q0.921875 0 1.34375 -0.53125q0.4375 -0.53125 0.671875 -1.359375l-3.75 -9.890625zm16.793396 -3.734375l2.75 0l0 7.359375q0 1.75 0.109375 2.265625q0.171875 0.84375 0.828125 1.359375q0.671875 0.5 1.8125 0.5q1.171875 0 1.765625 -0.484375q0.59375 -0.484375 0.71875 -1.171875q0.125 -0.703125 0.125 -2.3125l0 -7.515625l2.734375 0l0 7.140625q0 2.4375 -0.21875 3.453125q-0.21875 1.015625 -0.828125 1.71875q-0.59375 0.6875 -1.59375 1.109375q-1.0 0.40625 -2.609375 0.40625q-1.953125 0 -2.96875 -0.453125q-1.0 -0.453125 -1.59375 -1.171875q-0.578125 -0.71875 -0.75 -1.5q-0.28125 -1.171875 -0.28125 -3.453125l0 -7.25zm19.5979 13.59375l-2.609375 0l0 -9.828125q-1.4375 1.34375 -3.375 1.984375l0 -2.375q1.03125 -0.328125 2.21875 -1.25q1.203125 -0.9375 1.640625 -2.1875l2.125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#76a5af" d="m287.81104 383.17343l0 0c0 -5.809967 4.7099 -10.519897 10.519897 -10.519897l116.66098 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.66098 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m287.81104 383.17343l0 0c0 -5.809967 4.7099 -10.519897 10.519897 -10.519897l116.66098 0c2.790039 0 5.4658203 1.1083374 7.43869 3.0812073c1.9728699 1.9728699 3.0812073 4.648651 3.0812073 7.43869l0 42.07834c0 5.809967 -4.7099304 10.519897 -10.519897 10.519897l-116.66098 0c-5.8099976 0 -10.519897 -4.7099304 -10.519897 -10.519897z" fill-rule="nonzero"></path><path fill="#000000" d="m346.62677 411.1326l0 -13.59375l4.421875 0q2.5 0 3.265625 0.203125q1.15625 0.296875 1.9375 1.328125q0.796875 1.015625 0.796875 2.640625q0 1.25 -0.453125 2.109375q-0.453125 0.859375 -1.15625 1.34375q-0.703125 0.484375 -1.421875 0.640625q-0.984375 0.203125 -2.84375 0.203125l-1.796875 0l0 5.125l-2.75 0zm2.75 -11.296875l0 3.859375l1.5 0q1.625 0 2.171875 -0.21875q0.546875 -0.21875 0.859375 -0.671875q0.3125 -0.453125 0.3125 -1.046875q0 -0.75 -0.4375 -1.234375q-0.4375 -0.484375 -1.09375 -0.59375q-0.5 -0.09375 -1.984375 -0.09375l-1.328125 0zm9.037323 7.6875l2.515625 -0.3125q0.125 0.96875 0.65625 1.484375q0.53125 0.5 1.28125 0.5q0.796875 0 1.34375 -0.609375q0.5625 -0.609375 0.5625 -1.640625q0 -0.984375 -0.53125 -1.5625q-0.53125 -0.578125 -1.28125 -0.578125q-0.5 0 -1.203125 0.203125l0.28125 -2.125q1.0625 0.015625 1.609375 -0.46875q0.5625 -0.484375 0.5625 -1.296875q0 -0.6875 -0.40625 -1.09375q-0.40625 -0.40625 -1.078125 -0.40625q-0.671875 0 -1.140625 0.46875q-0.46875 0.46875 -0.578125 1.359375l-2.40625 -0.421875q0.25 -1.234375 0.75 -1.96875q0.515625 -0.734375 1.421875 -1.15625q0.90625 -0.421875 2.03125 -0.421875q1.90625 0 3.078125 1.21875q0.953125 1.0 0.953125 2.265625q0 1.796875 -1.953125 2.859375q1.15625 0.25 1.859375 1.125q0.703125 0.875 0.703125 2.109375q0 1.78125 -1.3125 3.046875q-1.296875 1.265625 -3.25 1.265625q-1.84375 0 -3.0625 -1.0625q-1.21875 -1.0625 -1.40625 -2.78125z" fill-rule="nonzero"></path></g></svg>
+
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 960.0 540.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="g115a30441b_0_35.0"><path d="m0 0l960.0 0l0 540.0l-960.0 0l0 -540.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#g115a30441b_0_35.0)"><path fill="#ffffff" d="m0 0l960.0 0l0 540.0l-960.0 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.72441 46.721786l894.55115 0l0 60.125984l-894.55115 0z" fill-rule="nonzero"></path><path fill="#000000" d="m63.47441 82.28053l3.5 0.875q-1.09375 4.328125 -3.96875 6.59375q-2.859375 2.265625 -6.984375 2.265625q-4.28125 0 -6.96875 -1.734375q-2.6875 -1.75 -4.09375 -5.046875q-1.390625 -3.3125 -1.390625 -7.109375q0 -4.140625 1.578125 -7.21875q1.578125 -3.078125 4.5 -4.671875q2.921875 -1.609375 6.421875 -1.609375q3.96875 0 6.671875 2.03125q2.71875 2.015625 3.796875 5.6875l-3.453125 0.8125q-0.921875 -2.890625 -2.6875 -4.203125q-1.75 -1.328125 -4.40625 -1.328125q-3.046875 0 -5.09375 1.46875q-2.046875 1.453125 -2.890625 3.921875q-0.828125 2.46875 -0.828125 5.09375q0 3.375 0.984375 5.890625q0.984375 2.515625 3.0625 3.765625q2.078125 1.25 4.5 1.25q2.953125 0 4.984375 -1.6875q2.046875 -1.703125 2.765625 -5.046875zm7.613434 9.28125l0 -19.1875l2.921875 0l0 2.90625q1.125 -2.03125 2.0625 -2.6875q0.953125 -0.65625 2.09375 -0.65625q1.640625 0 3.34375 1.046875l-1.125 3.015625q-1.1875 -0.703125 -2.375 -0.703125q-1.078125 0 -1.921875 0.640625q-0.84375 0.640625 -1.203125 1.78125q-0.546875 1.734375 -0.546875 3.796875l0 10.046875l-3.25 0zm25.039932 0l0 -2.8125q-2.25 3.25 -6.09375 3.25q-1.6875 0 -3.171875 -0.65625q-1.46875 -0.65625 -2.1875 -1.640625q-0.703125 -0.984375 -1.0 -2.40625q-0.203125 -0.953125 -0.203125 -3.03125l0 -11.890625l3.265625 0l0 10.640625q0 2.546875 0.1875 3.4375q0.3125 1.28125 1.296875 2.015625q1.0 0.734375 2.46875 0.734375q1.453125 0 2.734375 -0.75q1.296875 -0.75 1.828125 -2.046875q0.53125 -1.296875 0.53125 -3.75l0 -10.28125l3.25 0l0 19.1875l-2.90625 0zm8.182007 0l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm33.275757 -7.03125l3.203125 0.421875q-0.515625 3.296875 -2.6875 5.171875q-2.15625 1.875 -5.296875 1.875q-3.9375 0 -6.328125 -2.578125q-2.390625 -2.578125 -2.390625 -7.375q0 -3.109375 1.015625 -5.4375q1.03125 -2.34375 3.140625 -3.5q2.109375 -1.171875 4.578125 -1.171875q3.125 0 5.109375 1.59375q2.0 1.578125 2.546875 4.484375l-3.15625 0.484375q-0.453125 -1.9375 -1.609375 -2.90625q-1.140625 -0.984375 -2.765625 -0.984375q-2.453125 0 -4.0 1.765625q-1.53125 1.765625 -1.53125 5.578125q0 3.859375 1.484375 5.625q1.484375 1.75 3.875 1.75q1.90625 0 3.1875 -1.171875q1.28125 -1.1875 1.625 -3.625zm6.1484375 7.03125l0 -26.484375l3.25 0l0 9.5q2.28125 -2.640625 5.75 -2.640625q2.125 0 3.703125 0.84375q1.578125 0.84375 2.25 2.328125q0.671875 1.46875 0.671875 4.296875l0 12.15625l-3.25 0l0 -12.15625q0 -2.4375 -1.0625 -3.546875q-1.046875 -1.109375 -2.984375 -1.109375q-1.4375 0 -2.71875 0.75q-1.265625 0.734375 -1.8125 2.03125q-0.546875 1.28125 -0.546875 3.53125l0 10.5l-3.25 0zm31.552963 0l0 -26.484375l9.125 0q3.078125 0 4.703125 0.375q2.28125 0.53125 3.890625 1.90625q2.09375 1.765625 3.125 4.53125q1.046875 2.75 1.046875 6.28125q0 3.015625 -0.703125 5.359375q-0.703125 2.328125 -1.8125 3.859375q-1.09375 1.515625 -2.40625 2.390625q-1.3125 0.875 -3.171875 1.328125q-1.84375 0.453125 -4.25 0.453125l-9.546875 0zm3.5 -3.125l5.65625 0q2.625 0 4.109375 -0.484375q1.484375 -0.484375 2.375 -1.375q1.25 -1.25 1.9375 -3.34375q0.703125 -2.109375 0.703125 -5.109375q0 -4.15625 -1.375 -6.390625q-1.359375 -2.234375 -3.3125 -2.984375q-1.40625 -0.546875 -4.53125 -0.546875l-5.5625 0l0 20.234375zm23.050934 -19.625l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm6.9806213 -5.734375l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625zm19.960938 13.09375l0 -26.546875l2.96875 0l0 2.5q1.046875 -1.46875 2.359375 -2.203125q1.328125 -0.734375 3.203125 -0.734375q2.453125 0 4.328125 1.265625q1.890625 1.265625 2.84375 3.578125q0.953125 2.296875 0.953125 5.046875q0 2.9375 -1.0625 5.296875q-1.046875 2.359375 -3.0625 3.625q-2.015625 1.25 -4.234375 1.25q-1.625 0 -2.921875 -0.6875q-1.296875 -0.6875 -2.125 -1.734375l0 9.34375l-3.25 0zm2.953125 -16.84375q0 3.703125 1.5 5.484375q1.5 1.765625 3.625 1.765625q2.171875 0 3.703125 -1.828125q1.546875 -1.84375 1.546875 -5.6875q0 -3.671875 -1.515625 -5.5q-1.5 -1.828125 -3.59375 -1.828125q-2.078125 0 -3.671875 1.953125q-1.59375 1.9375 -1.59375 5.640625zm30.322617 7.125q-1.796875 1.53125 -3.46875 2.171875q-1.671875 0.625 -3.5937347 0.625q-3.15625 0 -4.859375 -1.546875q-1.6875 -1.546875 -1.6875 -3.953125q0 -1.40625 0.640625 -2.5625q0.640625 -1.171875 1.671875 -1.875q1.046875 -0.703125 2.34375 -1.0625q0.953125 -0.265625 2.890625 -0.5q3.9374847 -0.46875 5.7968597 -1.109375q0.015625 -0.671875 0.015625 -0.859375q0 -1.984375 -0.921875 -2.796875q-1.25 -1.09375 -3.703125 -1.09375q-2.2968597 0 -3.3906097 0.796875q-1.09375 0.796875 -1.609375 2.84375l-3.1875 -0.4375q0.4375 -2.03125 1.421875 -3.28125q1.0 -1.265625 2.875 -1.9375q1.890625 -0.6875 4.3593597 -0.6875q2.46875 0 4.0 0.578125q1.53125 0.578125 2.25 1.453125q0.734375 0.875 1.015625 2.21875q0.15625 0.828125 0.15625 3.0l0 4.328125q0 4.546875 0.203125 5.75q0.21875 1.1875 0.828125 2.296875l-3.390625 0q-0.5 -1.015625 -0.65625 -2.359375zm-0.265625 -7.265625q-1.765625 0.71875 -5.3125 1.21875q-1.9999847 0.296875 -2.8437347 0.65625q-0.828125 0.359375 -1.28125 1.0625q-0.4375 0.6875 -0.4375 1.53125q0 1.3125 0.984375 2.1875q0.984375 0.859375 2.875 0.859375q1.8749847 0 3.3437347 -0.828125q1.46875 -0.828125 2.15625 -2.25q0.515625 -1.09375 0.515625 -3.25l0 -1.1875zm15.619507 6.71875l0.46875 2.875q-1.375 0.28125 -2.46875 0.28125q-1.765625 0 -2.75 -0.5625q-0.96875 -0.5625 -1.375 -1.46875q-0.390625 -0.90625 -0.390625 -3.84375l0 -11.03125l-2.375 0l0 -2.53125l2.375 0l0 -4.75l3.234375 -1.953125l0 6.703125l3.28125 0l0 2.53125l-3.28125 0l0 11.21875q0 1.390625 0.171875 1.796875q0.171875 0.390625 0.5625 0.625q0.390625 0.234375 1.109375 0.234375q0.546875 0 1.4375 -0.125zm15.777191 -4.125l3.203125 0.421875q-0.515625 3.296875 -2.6875 5.171875q-2.15625 1.875 -5.2968445 1.875q-3.9375 0 -6.328125 -2.578125q-2.390625 -2.578125 -2.390625 -7.375q0 -3.109375 1.015625 -5.4375q1.03125 -2.34375 3.140625 -3.5q2.109375 -1.171875 4.578125 -1.171875q3.1249695 0 5.1093445 1.59375q2.0 1.578125 2.546875 4.484375l-3.15625 0.484375q-0.453125 -1.9375 -1.609375 -2.90625q-1.140625 -0.984375 -2.7655945 -0.984375q-2.453125 0 -4.0 1.765625q-1.53125 1.765625 -1.53125 5.578125q0 3.859375 1.484375 5.625q1.484375 1.75 3.875 1.75q1.9062195 0 3.1874695 -1.171875q1.28125 -1.1875 1.625 -3.625zm6.1484375 7.03125l0 -26.484375l3.25 0l0 9.5q2.28125 -2.640625 5.75 -2.640625q2.125 0 3.703125 0.84375q1.578125 0.84375 2.25 2.328125q0.671875 1.46875 0.671875 4.296875l0 12.15625l-3.25 0l0 -12.15625q0 -2.4375 -1.0625 -3.546875q-1.046875 -1.109375 -2.984375 -1.109375q-1.4375 0 -2.71875 0.75q-1.265625 0.734375 -1.8125 2.03125q-0.546875 1.28125 -0.546875 3.53125l0 10.5l-3.25 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m145.72684 103.48555l673.67993 0l0 505.26257l-673.67993 0z" fill-rule="nonzero"></path><g transform="matrix(0.7017498687664041 0.0 0.0 0.7017535433070867 145.72683779527557 103.48555144356955)"><clipPath id="g115a30441b_0_35.1"><path d="m-2.842171E-14 0l960.0 0l0 720.0l-960.0 0z" clip-rule="nonzero"></path></clipPath><image clip-path="url(#g115a30441b_0_35.1)" fill="#000" width="960.0" height="720.0" x="0.0" y="0.0" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"></image></g></g></svg>
+
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 960.0 540.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="g1586814eb6_0_6.0"><path d="m0 0l960.0 0l0 540.0l-960.0 0l0 -540.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#g1586814eb6_0_6.0)"><path fill="#ffffff" d="m0 0l960.0 0l0 540.0l-960.0 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.72441 46.721786l894.55115 0l0 60.125984l-894.55115 0z" fill-rule="nonzero"></path><path fill="#000000" d="m63.47441 82.28053l3.5 0.875q-1.09375 4.328125 -3.96875 6.59375q-2.859375 2.265625 -6.984375 2.265625q-4.28125 0 -6.96875 -1.734375q-2.6875 -1.75 -4.09375 -5.046875q-1.390625 -3.3125 -1.390625 -7.109375q0 -4.140625 1.578125 -7.21875q1.578125 -3.078125 4.5 -4.671875q2.921875 -1.609375 6.421875 -1.609375q3.96875 0 6.671875 2.03125q2.71875 2.015625 3.796875 5.6875l-3.453125 0.8125q-0.921875 -2.890625 -2.6875 -4.203125q-1.75 -1.328125 -4.40625 -1.328125q-3.046875 0 -5.09375 1.46875q-2.046875 1.453125 -2.890625 3.921875q-0.828125 2.46875 -0.828125 5.09375q0 3.375 0.984375 5.890625q0.984375 2.515625 3.0625 3.765625q2.078125 1.25 4.5 1.25q2.953125 0 4.984375 -1.6875q2.046875 -1.703125 2.765625 -5.046875zm6.441559 -0.3125q0 -5.328125 2.953125 -7.890625q2.484375 -2.140625 6.03125 -2.140625q3.96875 0 6.46875 2.59375q2.515625 2.59375 2.515625 7.171875q0 3.703125 -1.109375 5.828125q-1.109375 2.109375 -3.234375 3.296875q-2.125 1.171875 -4.640625 1.171875q-4.015625 0 -6.5 -2.578125q-2.484375 -2.59375 -2.484375 -7.453125zm3.34375 0q0 3.6875 1.59375 5.53125q1.609375 1.828125 4.046875 1.828125q2.421875 0 4.03125 -1.84375q1.609375 -1.84375 1.609375 -5.625q0 -3.5625 -1.625 -5.390625q-1.609375 -1.828125 -4.015625 -1.828125q-2.4375 0 -4.046875 1.828125q-1.59375 1.8125 -1.59375 5.5zm18.541382 9.59375l0 -26.484375l3.265625 0l0 26.484375l-3.265625 0zm8.293121 0l0 -26.484375l3.265625 0l0 26.484375l-3.265625 0zm21.511871 -6.171875l3.359375 0.40625q-0.796875 2.953125 -2.953125 4.578125q-2.140625 1.625 -5.484375 1.625q-4.21875 0 -6.6875 -2.59375q-2.453125 -2.59375 -2.453125 -7.28125q0 -4.828125 2.484375 -7.5q2.5 -2.6875 6.46875 -2.6875q3.859375 0 6.296875 2.625q2.4375 2.625 2.4375 7.375q0 0.28125 -0.015625 0.859375l-14.3125 0q0.171875 3.171875 1.78125 4.859375q1.609375 1.671875 4.015625 1.671875q1.78125 0 3.046875 -0.9375q1.265625 -0.953125 2.015625 -3.0zm-10.6875 -5.265625l10.71875 0q-0.21875 -2.421875 -1.234375 -3.625q-1.546875 -1.890625 -4.015625 -1.890625q-2.25 0 -3.78125 1.5q-1.515625 1.5 -1.6875 4.015625zm30.822632 4.40625l3.203125 0.421875q-0.515625 3.296875 -2.6875 5.171875q-2.15625 1.875 -5.296875 1.875q-3.9375 0 -6.328125 -2.578125q-2.390625 -2.578125 -2.390625 -7.375q0 -3.109375 1.015625 -5.4375q1.03125 -2.34375 3.140625 -3.5q2.109375 -1.171875 4.578125 -1.171875q3.125 0 5.109375 1.59375q2.0 1.578125 2.546875 4.484375l-3.15625 0.484375q-0.453125 -1.9375 -1.609375 -2.90625q-1.140625 -0.984375 -2.765625 -0.984375q-2.453125 0 -4.0 1.765625q-1.53125 1.765625 -1.53125 5.578125q0 3.859375 1.484375 5.625q1.484375 1.75 3.875 1.75q1.90625 0 3.1875 -1.171875q1.28125 -1.1875 1.625 -3.625zm13.2578125 4.125l0.46875 2.875q-1.375 0.28125 -2.46875 0.28125q-1.765625 0 -2.75 -0.5625q-0.96875 -0.5625 -1.375 -1.46875q-0.390625 -0.90625 -0.390625 -3.84375l0 -11.03125l-2.375 0l0 -2.53125l2.375 0l0 -4.75l3.234375 -1.953125l0 6.703125l3.28125 0l0 2.53125l-3.28125 0l0 11.21875q0 1.390625 0.171875 1.796875q0.171875 0.390625 0.5625 0.625q0.390625 0.234375 1.109375 0.234375q0.546875 0 1.4375 -0.125zm3.2772064 -19.84375l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm7.0743713 -9.59375q0 -5.328125 2.953125 -7.890625q2.484375 -2.140625 6.03125 -2.140625q3.96875 0 6.46875 2.59375q2.515625 2.59375 2.515625 7.171875q0 3.703125 -1.109375 5.828125q-1.109375 2.109375 -3.234375 3.296875q-2.125 1.171875 -4.640625 1.171875q-4.015625 0 -6.5 -2.578125q-2.484375 -2.59375 -2.484375 -7.453125zm3.34375 0q0 3.6875 1.59375 5.53125q1.609375 1.828125 4.046875 1.828125q2.421875 0 4.03125 -1.84375q1.609375 -1.84375 1.609375 -5.625q0 -3.5625 -1.625 -5.390625q-1.609375 -1.828125 -4.015625 -1.828125q-2.4375 0 -4.046875 1.828125q-1.59375 1.8125 -1.59375 5.5zm18.619507 9.59375l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm19.463257 -5.734375l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625zm20.867188 -9.75l0 -3.703125l3.703125 0l0 3.703125l-3.703125 0zm0 15.484375l0 -3.703125l3.703125 0l0 3.703125l-3.703125 0zm20.148163 0l0 -26.484375l5.265625 0l6.28125 18.75q0.859375 2.625 1.265625 3.921875q0.4375 -1.4375 1.40625 -4.25l6.34375 -18.421875l4.703125 0l0 26.484375l-3.375 0l0 -22.171875l-7.6875 22.171875l-3.171875 0l-7.65625 -22.546875l0 22.546875l-3.375 0zm43.29773 -2.359375q-1.796875 1.53125 -3.46875 2.171875q-1.671875 0.625 -3.59375 0.625q-3.15625 0 -4.859375 -1.546875q-1.6875 -1.546875 -1.6875 -3.953125q0 -1.40625 0.640625 -2.5625q0.640625 -1.171875 1.671875 -1.875q1.046875 -0.703125 2.34375 -1.0625q0.953125 -0.265625 2.890625 -0.5q3.9375 -0.46875 5.796875 -1.109375q0.015625 -0.671875 0.015625 -0.859375q0 -1.984375 -0.921875 -2.796875q-1.25 -1.09375 -3.703125 -1.09375q-2.296875 0 -3.390625 0.796875q-1.09375 0.796875 -1.609375 2.84375l-3.1875 -0.4375q0.4375 -2.03125 1.421875 -3.28125q1.0 -1.265625 2.875 -1.9375q1.890625 -0.6875 4.359375 -0.6875q2.46875 0 4.0 0.578125q1.53125 0.578125 2.25 1.453125q0.734375 0.875 1.015625 2.21875q0.15625 0.828125 0.15625 3.0l0 4.328125q0 4.546875 0.203125 5.75q0.21875 1.1875 0.828125 2.296875l-3.390625 0q-0.5 -1.015625 -0.65625 -2.359375zm-0.265625 -7.265625q-1.765625 0.71875 -5.3125 1.21875q-2.0 0.296875 -2.84375 0.65625q-0.828125 0.359375 -1.28125 1.0625q-0.4375 0.6875 -0.4375 1.53125q0 1.3125 0.984375 2.1875q0.984375 0.859375 2.875 0.859375q1.875 0 3.34375 -0.828125q1.46875 -0.828125 2.15625 -2.25q0.515625 -1.09375 0.515625 -3.25l0 -1.1875zm8.510132 9.625l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm20.775757 -22.75l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm9.058746 0l0 -16.65625l-2.875 0l0 -2.53125l2.875 0l0 -2.046875q0 -1.921875 0.34375 -2.859375q0.46875 -1.265625 1.640625 -2.046875q1.1875 -0.796875 3.328125 -0.796875q1.375 0 3.03125 0.328125l-0.484375 2.828125q-1.015625 -0.171875 -1.921875 -0.171875q-1.484375 0 -2.09375 0.640625q-0.609375 0.625 -0.609375 2.359375l0 1.765625l3.734375 0l0 2.53125l-3.734375 0l0 16.65625l-3.234375 0zm22.730347 -6.171875l3.359375 0.40625q-0.796875 2.953125 -2.953125 4.578125q-2.140625 1.625 -5.484375 1.625q-4.21875 0 -6.6875 -2.59375q-2.453125 -2.59375 -2.453125 -7.28125q0 -4.828125 2.484375 -7.5q2.5 -2.6875 6.46875 -2.6875q3.859375 0 6.296875 2.625q2.4375 2.625 2.4375 7.375q0 0.28125 -0.015625 0.859375l-14.3125 0q0.171875 3.171875 1.78125 4.859375q1.609375 1.671875 4.015625 1.671875q1.78125 0 3.046875 -0.9375q1.265625 -0.953125 2.015625 -3.0zm-10.6875 -5.265625l10.71875 0q-0.21875 -2.421875 -1.234375 -3.625q-1.546875 -1.890625 -4.015625 -1.890625q-2.25 0 -3.78125 1.5q-1.515625 1.5 -1.6875 4.015625zm17.010132 5.703125l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625zm27.070312 2.828125l0.46875 2.875q-1.375 0.28125 -2.46875 0.28125q-1.765625 0 -2.75 -0.5625q-0.96875 -0.5625 -1.375 -1.46875q-0.390625 -0.90625 -0.390625 -3.84375l0 -11.03125l-2.375 0l0 -2.53125l2.375 0l0 -4.75l3.234375 -1.953125l0 6.703125l3.28125 0l0 2.53125l-3.28125 0l0 11.21875q0 1.390625 0.171875 1.796875q0.171875 0.390625 0.5625 0.625q0.390625 0.234375 1.109375 0.234375q0.546875 0 1.4375 -0.125zm1.9647217 -2.828125l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.08399 481.27823l894.5512 0l0 46.015717l-894.5512 0z" fill-rule="nonzero"></path><path fill="#000000" d="m46.005863 508.1982l0 -12.0l-4.46875 0l0 -1.59375l10.765625 0l0 1.59375l-4.5 0l0 12.0l-1.796875 0zm14.474106 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547596 2.265625l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.2187538 -1.328125 -1.2187538 -3.796875q0 -1.59375 0.5156288 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.890625 3.609375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm10.375717 0l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm10.391342 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm10.566696 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 2.390625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.047592 4.9375l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm8.6875 -2.9375l1.6562424 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.7031174 -0.34375 -1.0781174 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.8281174 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9374924 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.999992 6.71875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.610092 1.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547592 2.265625l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.21875 0.671875l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.46875 -5.015625l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm0 7.953125l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0z" fill-rule="nonzero"></path><path fill="#0097a7" d="m186.46445 508.1982l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm14.031967 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm5.183304 0l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270538 5.28125l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.188217 1.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.46875 -5.015625l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm0 7.953125l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm3.4645538 0.234375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm5.183304 0l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm12.823929 -0.234375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm16.016342 1.75l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm11.844482 5.875l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm7.0625 0l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm11.152039 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm8.9626465 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.03125 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469482 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.641357 0q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm8.610077 1.984375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.46875 2.9375l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm4.089569 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.266327 4.921875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.931427 0.8125l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625305 -2.5 0.5625305q-1.765625 0 -2.859375 -0.7969055q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm8.047607 5.34375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm6.4332886 3.546875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.844482 4.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.6032715 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 -6.734375l0 -1.9375l1.65625 0l0 1.9375l-1.65625 0zm-2.125 15.4844055l0.3125 -1.4219055q0.5 0.125 0.796875 0.125q0.515625 0 0.765625 -0.34375q0.25 -0.328125 0.25 -1.6875l0 -10.359375l1.65625 0l0 10.390625q0 1.828125 -0.46875 2.546875q-0.59375 0.9219055 -2.0 0.9219055q-0.671875 0 -1.3125 -0.171875zm13.019836 -7.0000305l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547577 2.265625l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm6.546875 2.109375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.8551941 -1.4375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm8.7499695 3.171875l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm12.870789 -1.453125q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm8.962677 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.03125 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.469452 4.9375l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm8.641357 0q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm8.610107 1.984375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.7812805 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.8437805 -0.46875 -2.5625305 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375305 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.1562805 0 -1.6406555 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.4687805 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.9219055 0 -2.9375305 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm8.7500305 3.171875l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm8.261414 -0.234375l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.660461 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.1448364 0l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm9.328125 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm2.8791504 0.234375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm6.5739746 -0.234375l0 -13.59375l1.796875 0l0 6.734375l6.765625 -6.734375l2.4375 0l-5.703125 5.5l5.953125 8.09375l-2.375 0l-4.84375 -6.890625l-2.234375 2.171875l0 4.71875l-1.796875 0zm19.052917 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860046 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm7.3288574 8.65625l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm11.906982 -3.78125l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978333 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0787964 4.9375l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm10.391357 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.5355225 0l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm11.526978 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm13.65625 1.4375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm-0.0041503906 5.28125l0 -1.21875l11.0625 0l0 1.21875l-11.0625 0zm12.313232 -3.78125l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm4.1519775 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.266357 4.921875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2283936 0l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978271 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm7.7351074 3.4375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125z" fill-rule="nonzero"></path><path stroke="#0097a7" stroke-width="1.3671875" stroke-linecap="butt" d="m185.21445 510.1761l560.99927 0" fill-rule="nonzero"></path><a xlink:href="https://www.google.com/url?q=https://dev.arvados.org/projects/arvados/wiki/Keep_manifest_format&sa=D&ust=1478895969188000&usg=AFQjCNHMNIzr5ezz4laFKPqTOrFHC9sgsA" target="_blank" rel="noreferrer"><path fill="transparent" fill-opacity="0" d="m185.21445 512.15173l0 -20.84253l560.99927 0l0 20.84253z" fill-rule="evenodd"></path></a><path fill="#000000" fill-opacity="0.0" d="m178.12337 46.721786l600.2048 0l0 473.36218l-600.2048 0z" fill-rule="nonzero"></path><g transform="matrix(0.6538178477690288 0.0 0.0 0.6538152230971128 178.12336036745407 46.72178477690289)"><clipPath id="g1586814eb6_0_6.1"><path d="m0 1.4210855E-14l918.0 0l0 724.0l-918.0 0z" clip-rule="nonzero"></path></clipPath><image clip-path="url(#g1586814eb6_0_6.1)" fill="#000" width="918.0" height="724.0" x="0.0" y="0.0" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"></image></g></g></svg>
+
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 960.0 540.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="g150061aa58_0_0.0"><path d="m0 0l960.0 0l0 540.0l-960.0 0l0 -540.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#g150061aa58_0_0.0)"><path fill="#ffffff" d="m0 0l960.0 0l0 540.0l-960.0 0z" fill-rule="nonzero"></path><path fill="#eeeeee" d="m312.64752 161.47145c-1.304718 -6.8049164 2.9787598 -13.541397 11.032776 -17.350906c8.053986 -3.8095093 18.466064 -4.023941 26.817963 -0.5523224l0 0c2.9583435 -3.9569397 8.373169 -6.6889496 14.606506 -7.3696136c6.2333374 -0.6806488 12.55304 0.769989 17.047424 3.9131317l0 0c2.5202026 -3.5875702 7.46875 -5.9979553 13.08963 -6.375824c5.6208496 -0.37786865 11.1185 1.3302612 14.542084 4.5182495l0 0c4.5532227 -3.8025818 11.797455 -5.40361 18.598114 -4.110321c6.800659 1.2933044 11.936279 5.2486267 13.184662 10.1545105l0 0c5.5782166 1.0799713 10.224731 3.8253632 12.739075 7.5268555c2.5143433 3.7014923 2.6498718 7.995987 0.3715515 11.773926l0 0c5.4933167 5.074188 6.778412 11.835541 3.375702 17.760818c-3.40271 5.9252777 -10.982025 10.124237 -19.909393 11.029907c-0.062927246 5.561264 -4.359955 10.664215 -11.234833 13.341904c-6.874878 2.6776886 -15.253998 2.5119781 -21.907654 -0.43325806c-2.8341675 6.660553 -10.811493 11.56134 -20.485474 12.585007c-9.673981 1.0236511 -19.310303 -2.013321 -24.745697 -7.798828c-6.662628 2.851654 -14.657257 3.6731415 -22.18042 2.279129c-7.5231934 -1.3939972 -13.941193 -4.8860626 -17.806213 -9.688431l0 0c-6.808319 0.565506 -13.391052 -1.9381409 -16.481201 -6.268387c-3.0901794 -4.330246 -2.0299683 -9.565308 2.6544495 -13.107056l0 0c-6.073517 -2.53714 -9.172607 -7.571686 -7.6812134 -12.478317c1.491394 -4.9066315 7.2353516 -8.573486 14.236572 -9.08844z" fill-rule="nonzero"></path><path fill="#eeeeee" d="m347.71796 228.58267c0 1.2978516 -1.052124 2.3499603 -2.3499756 2.3499603c-1.297821 0 -2.349945 -1.0521088 -2.349945 -2.3499603c0 -1.2978363 1.052124 -2.349945 2.349945 -2.349945c1.2978516 0 2.3499756 1.0521088 2.3499756 2.349945z" fill-rule="nonzero"></path><path fill="#eeeeee" d="m351.94028 225.65413c0 2.5956879 -2.1042175 4.6999207 -4.69989 4.6999207c-2.5957031 0 -4.6999207 -2.1042328 -4.6999207 -4.6999207c0 -2.5956879 2.1042175 -4.6999054 4.6999207 -4.6999054c2.5956726 0 4.69989 2.1042175 4.69989 4.6999054z" fill-rule="nonzero"></path><path fill="#eeeeee" d="m358.6943 218.76582c0 3.8935394 -3.1563416 7.0498657 -7.0498657 7.0498657c-3.8935242 0 -7.0498657 -3.1563263 -7.0498657 -7.0498657c0 -3.8935394 3.1563416 -7.0498657 7.0498657 -7.0498657c3.8935242 0 7.0498657 3.1563263 7.0498657 7.0498657z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m315.61838 184.52805l0 0c-3.3113708 0.18397522 -6.6223755 -0.35913086 -9.488464 -1.5564117m17.860107 18.588898c-1.331543 0.3761902 -2.7273254 0.6266632 -4.151306 0.7449341m39.921875 7.4392548l0 0c-1.0014954 -1.0660095 -1.8399963 -2.2051392 -2.5012207 -3.3979645m48.75699 -5.0752716c-0.14724731 1.264389 -0.48202515 2.5141602 -0.99871826 3.7284546m20.857605 -26.765305l0 0c7.5073853 2.592987 12.245026 8.014023 12.17807 13.934677m16.547363 -28.776062c-1.2158203 2.0160675 -3.0718994 3.8045044 -5.422699 5.225067m-7.589813 -24.612915l0 0c0.20715332 0.81414795 0.30303955 1.6405334 0.28631592 2.4677124m-34.918304 -5.346176l0 0c0.7065735 -1.1384583 1.642334 -2.198471 2.7781372 -3.1470337m-28.761261 4.6465454l0 0c0.28826904 -0.9408264 0.74020386 -1.8525238 1.345459 -2.7141113m-31.83963 3.6362305l0 0c1.767273 0.7345886 3.4022217 1.6187592 4.8689575 2.6330566m-41.849762 18.061127l0 0c-0.3857727 -0.9061127 -0.6699219 -1.8324738 -0.84973145 -2.7703857" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m312.64752 161.47145c-1.304718 -6.8049164 2.9787598 -13.541397 11.032776 -17.350906c8.053986 -3.8095093 18.466064 -4.023941 26.817963 -0.5523224l0 0c2.9583435 -3.9569397 8.373169 -6.6889496 14.606506 -7.3696136c6.2333374 -0.6806488 12.55304 0.769989 17.047424 3.9131317l0 0c2.5202026 -3.5875702 7.46875 -5.9979553 13.08963 -6.375824c5.6208496 -0.37786865 11.1185 1.3302612 14.542084 4.5182495l0 0c4.5532227 -3.8025818 11.797455 -5.40361 18.598114 -4.110321c6.800659 1.2933044 11.936279 5.2486267 13.184662 10.1545105l0 0c5.5782166 1.0799713 10.224731 3.8253632 12.739075 7.5268555c2.5143433 3.7014923 2.6498718 7.995987 0.3715515 11.773926l0 0c5.4933167 5.074188 6.778412 11.835541 3.375702 17.760818c-3.40271 5.9252777 -10.982025 10.124237 -19.909393 11.029907c-0.062927246 5.561264 -4.359955 10.664215 -11.234833 13.341904c-6.874878 2.6776886 -15.253998 2.5119781 -21.907654 -0.43325806c-2.8341675 6.660553 -10.811493 11.56134 -20.485474 12.585007c-9.673981 1.0236511 -19.310303 -2.013321 -24.745697 -7.798828c-6.662628 2.851654 -14.657257 3.6731415 -22.18042 2.279129c-7.5231934 -1.3939972 -13.941193 -4.8860626 -17.806213 -9.688431l0 0c-6.808319 0.565506 -13.391052 -1.9381409 -16.481201 -6.268387c-3.0901794 -4.330246 -2.0299683 -9.565308 2.6544495 -13.107056l0 0c-6.073517 -2.53714 -9.172607 -7.571686 -7.6812134 -12.478317c1.491394 -4.9066315 7.2353516 -8.573486 14.236572 -9.08844z" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m347.71796 228.58267c0 1.2978516 -1.052124 2.3499603 -2.3499756 2.3499603c-1.297821 0 -2.349945 -1.0521088 -2.349945 -2.3499603c0 -1.2978363 1.052124 -2.349945 2.349945 -2.349945c1.2978516 0 2.3499756 1.0521088 2.3499756 2.349945z" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m351.94028 225.65413c0 2.5956879 -2.1042175 4.6999207 -4.69989 4.6999207c-2.5957031 0 -4.6999207 -2.1042328 -4.6999207 -4.6999207c0 -2.5956879 2.1042175 -4.6999054 4.6999207 -4.6999054c2.5956726 0 4.69989 2.1042175 4.69989 4.6999054z" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m358.6943 218.76582c0 3.8935394 -3.1563416 7.0498657 -7.0498657 7.0498657c-3.8935242 0 -7.0498657 -3.1563263 -7.0498657 -7.0498657c0 -3.8935394 3.1563416 -7.0498657 7.0498657 -7.0498657c3.8935242 0 7.0498657 3.1563263 7.0498657 7.0498657z" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m315.61838 184.52805l0 0c-3.3113708 0.18397522 -6.6223755 -0.35913086 -9.488464 -1.5564117m17.860107 18.588898c-1.331543 0.3761902 -2.7273254 0.6266632 -4.151306 0.7449341m39.921875 7.4392548l0 0c-1.0014954 -1.0660095 -1.8399963 -2.2051392 -2.5012207 -3.3979645m48.75699 -5.0752716c-0.14724731 1.264389 -0.48202515 2.5141602 -0.99871826 3.7284546m20.857605 -26.765305l0 0c7.5073853 2.592987 12.245026 8.014023 12.17807 13.934677m16.547363 -28.776062c-1.2158203 2.0160675 -3.0718994 3.8045044 -5.422699 5.225067m-7.589813 -24.612915l0 0c0.20715332 0.81414795 0.30303955 1.6405334 0.28631592 2.4677124m-34.918304 -5.346176l0 0c0.7065735 -1.1384583 1.642334 -2.198471 2.7781372 -3.1470337m-28.761261 4.6465454l0 0c0.28826904 -0.9408264 0.74020386 -1.8525238 1.345459 -2.7141113m-31.83963 3.6362305l0 0c1.767273 0.7345886 3.4022217 1.6187592 4.8689575 2.6330566m-41.849762 18.061127l0 0c-0.3857727 -0.9061127 -0.6699219 -1.8324738 -0.84973145 -2.7703857" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.72441 46.721786l894.55115 0l0 60.125984l-894.55115 0z" fill-rule="nonzero"></path><path fill="#000000" d="m44.63066 91.56178l0 -26.484375l11.75 0q3.53125 0 5.375 0.71875q1.84375 0.703125 2.9375 2.515625q1.109375 1.8125 1.109375 3.984375q0 2.828125 -1.828125 4.765625q-1.8125 1.921875 -5.625 2.453125q1.390625 0.671875 2.109375 1.3125q1.53125 1.40625 2.90625 3.53125l4.609375 7.203125l-4.40625 0l-3.5 -5.515625q-1.546875 -2.375 -2.546875 -3.640625q-0.984375 -1.265625 -1.765625 -1.765625q-0.78125 -0.515625 -1.59375 -0.71875q-0.609375 -0.125 -1.953125 -0.125l-4.078125 0l0 11.765625l-3.5 0zm3.5 -14.796875l7.546875 0q2.390625 0 3.75 -0.5q1.359375 -0.5 2.0625 -1.578125q0.703125 -1.09375 0.703125 -2.390625q0 -1.875 -1.375 -3.078125q-1.359375 -1.21875 -4.296875 -1.21875l-8.390625 0l0 8.765625zm36.12906 8.625l3.359375 0.40625q-0.796875 2.953125 -2.953125 4.578125q-2.140625 1.625 -5.484375 1.625q-4.21875 0 -6.6875 -2.59375q-2.453125 -2.59375 -2.453125 -7.28125q0 -4.828125 2.484375 -7.5q2.5 -2.6875 6.46875 -2.6875q3.859375 0 6.296875 2.625q2.4375 2.625 2.4375 7.375q0 0.28125 -0.015625 0.859375l-14.3125 0q0.171875 3.171875 1.78125 4.859375q1.609375 1.671875 4.015625 1.671875q1.78125 0 3.046875 -0.9375q1.265625 -0.953125 2.015625 -3.0zm-10.6875 -5.265625l10.71875 0q-0.21875 -2.421875 -1.234375 -3.625q-1.546875 -1.890625 -4.015625 -1.890625q-2.25 0 -3.78125 1.5q-1.515625 1.5 -1.6875 4.015625zm30.822632 9.078125q-1.796875 1.53125 -3.46875 2.171875q-1.671875 0.625 -3.59375 0.625q-3.15625 0 -4.859375 -1.546875q-1.6875 -1.546875 -1.6875 -3.953125q0 -1.40625 0.640625 -2.5625q0.640625 -1.171875 1.671875 -1.875q1.046875 -0.703125 2.34375 -1.0625q0.953125 -0.265625 2.890625 -0.5q3.9375 -0.46875 5.796875 -1.109375q0.015625 -0.671875 0.015625 -0.859375q0 -1.984375 -0.921875 -2.796875q-1.25 -1.09375 -3.703125 -1.09375q-2.296875 0 -3.390625 0.796875q-1.09375 0.796875 -1.609375 2.84375l-3.1875 -0.4375q0.4375 -2.03125 1.421875 -3.28125q1.0 -1.265625 2.875 -1.9375q1.890625 -0.6875 4.359375 -0.6875q2.46875 0 4.0 0.578125q1.53125 0.578125 2.25 1.453125q0.734375 0.875 1.015625 2.21875q0.15625 0.828125 0.15625 3.0l0 4.328125q0 4.546875 0.203125 5.75q0.21875 1.1875 0.828125 2.296875l-3.390625 0q-0.5 -1.015625 -0.65625 -2.359375zm-0.265625 -7.265625q-1.765625 0.71875 -5.3125 1.21875q-2.0 0.296875 -2.84375 0.65625q-0.828125 0.359375 -1.28125 1.0625q-0.4375 0.6875 -0.4375 1.53125q0 1.3125 0.984375 2.1875q0.984375 0.859375 2.875 0.859375q1.875 0 3.34375 -0.828125q1.46875 -0.828125 2.15625 -2.25q0.515625 -1.09375 0.515625 -3.25l0 -1.1875zm20.963257 9.625l0 -2.421875q-1.828125 2.859375 -5.375 2.859375q-2.28125 0 -4.21875 -1.265625q-1.921875 -1.265625 -2.984375 -3.53125q-1.046875 -2.265625 -1.046875 -5.21875q0 -2.875 0.953125 -5.203125q0.96875 -2.34375 2.875 -3.59375q1.921875 -1.25 4.28125 -1.25q1.734375 0 3.09375 0.734375q1.359375 0.734375 2.203125 1.90625l0 -9.5l3.234375 0l0 26.484375l-3.015625 0zm-10.28125 -9.578125q0 3.6875 1.546875 5.515625q1.5625 1.828125 3.671875 1.828125q2.125 0 3.609375 -1.75q1.5 -1.75 1.5 -5.3125q0 -3.953125 -1.515625 -5.78125q-1.515625 -1.84375 -3.734375 -1.84375q-2.171875 0 -3.625 1.765625q-1.453125 1.765625 -1.453125 5.578125zm18.603882 -13.171875l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm8.277496 0l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm20.166382 1.59375l3.15625 0.46875q0.203125 1.453125 1.109375 2.125q1.203125 0.90625 3.296875 0.90625q2.265625 0 3.484375 -0.90625q1.234375 -0.90625 1.671875 -2.53125q0.25 -0.984375 0.234375 -4.171875q-2.125 2.515625 -5.3125 2.515625q-3.953125 0 -6.125 -2.84375q-2.171875 -2.859375 -2.171875 -6.859375q0 -2.75 1.0 -5.0625q1.0 -2.328125 2.875 -3.59375q1.890625 -1.265625 4.4375 -1.265625q3.40625 0 5.609375 2.75l0 -2.3125l3.0 0l0 16.578125q0 4.484375 -0.921875 6.359375q-0.90625 1.875 -2.890625 2.953125q-1.96875 1.078125 -4.859375 1.078125q-3.4375 0 -5.5625 -1.546875q-2.109375 -1.53125 -2.03125 -4.640625zm2.6875 -11.53125q0 3.78125 1.5 5.515625q1.5 1.734375 3.765625 1.734375q2.234375 0 3.75 -1.71875q1.515625 -1.734375 1.515625 -5.421875q0 -3.515625 -1.5625 -5.296875q-1.5625 -1.796875 -3.765625 -1.796875q-2.171875 0 -3.6875 1.765625q-1.515625 1.75 -1.515625 5.21875zm16.228882 10.390625l7.671875 -27.390625l2.609375 0l-7.65625 27.390625l-2.625 0zm16.355331 -0.453125l-5.875 -19.1875l3.359375 0l3.046875 11.078125l1.140625 4.109375q0.078125 -0.296875 1.0 -3.953125l3.046875 -11.234375l3.34375 0l2.875 11.125l0.953125 3.671875l1.109375 -3.703125l3.28125 -11.09375l3.171875 0l-6.0 19.1875l-3.375 0l-3.0625 -11.484375l-0.734375 -3.28125l-3.890625 14.765625l-3.390625 0zm23.379059 0l0 -19.1875l2.921875 0l0 2.90625q1.125 -2.03125 2.0625 -2.6875q0.953125 -0.65625 2.09375 -0.65625q1.640625 0 3.34375 1.046875l-1.125 3.015625q-1.1875 -0.703125 -2.375 -0.703125q-1.078125 0 -1.921875 0.640625q-0.84375 0.640625 -1.203125 1.78125q-0.546875 1.734375 -0.546875 3.796875l0 10.046875l-3.25 0zm12.477432 -22.75l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm15.386871 -2.90625l0.46875 2.875q-1.375 0.28125 -2.46875 0.28125q-1.765625 0 -2.75 -0.5625q-0.96875 -0.5625 -1.375 -1.46875q-0.390625 -0.90625 -0.390625 -3.84375l0 -11.03125l-2.375 0l0 -2.53125l2.375 0l0 -4.75l3.234375 -1.953125l0 6.703125l3.28125 0l0 2.53125l-3.28125 0l0 11.21875q0 1.390625 0.171875 1.796875q0.171875 0.390625 0.5625 0.625q0.390625 0.234375 1.109375 0.234375q0.546875 0 1.4375 -0.125zm3.2772064 -19.84375l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm8.277496 0l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm20.166382 1.59375l3.15625 0.46875q0.203125 1.453125 1.109375 2.125q1.203125 0.90625 3.296875 0.90625q2.2655945 0 3.4843445 -0.90625q1.234375 -0.90625 1.671875 -2.53125q0.25 -0.984375 0.234375 -4.171875q-2.125 2.515625 -5.3124695 2.515625q-3.953125 0 -6.125 -2.84375q-2.171875 -2.859375 -2.171875 -6.859375q0 -2.75 1.0 -5.0625q1.0 -2.328125 2.875 -3.59375q1.890625 -1.265625 4.4375 -1.265625q3.4062195 0 5.6093445 2.75l0 -2.3125l3.0 0l0 16.578125q0 4.484375 -0.921875 6.359375q-0.90625 1.875 -2.890625 2.953125q-1.96875 1.078125 -4.8593445 1.078125q-3.4375 0 -5.5625 -1.546875q-2.109375 -1.53125 -2.03125 -4.640625zm2.6875 -11.53125q0 3.78125 1.5 5.515625q1.5 1.734375 3.765625 1.734375q2.2343445 0 3.7499695 -1.71875q1.515625 -1.734375 1.515625 -5.421875q0 -3.515625 -1.5625 -5.296875q-1.5625 -1.796875 -3.7655945 -1.796875q-2.171875 0 -3.6875 1.765625q-1.515625 1.75 -1.515625 5.21875zm41.552948 7.578125q-1.796875 1.53125 -3.46875 2.171875q-1.671875 0.625 -3.59375 0.625q-3.15625 0 -4.859375 -1.546875q-1.6875 -1.546875 -1.6875 -3.953125q0 -1.40625 0.640625 -2.5625q0.640625 -1.171875 1.671875 -1.875q1.046875 -0.703125 2.34375 -1.0625q0.953125 -0.265625 2.890625 -0.5q3.9375 -0.46875 5.796875 -1.109375q0.015625 -0.671875 0.015625 -0.859375q0 -1.984375 -0.921875 -2.796875q-1.25 -1.09375 -3.703125 -1.09375q-2.296875 0 -3.390625 0.796875q-1.09375 0.796875 -1.609375 2.84375l-3.1875 -0.4375q0.4375 -2.03125 1.421875 -3.28125q1.0 -1.265625 2.875 -1.9375q1.890625 -0.6875 4.359375 -0.6875q2.46875 0 4.0 0.578125q1.53125 0.578125 2.25 1.453125q0.734375 0.875 1.015625 2.21875q0.15625 0.828125 0.15625 3.0l0 4.328125q0 4.546875 0.203125 5.75q0.21875 1.1875 0.828125 2.296875l-3.390625 0q-0.5 -1.015625 -0.65625 -2.359375zm-0.265625 -7.265625q-1.765625 0.71875 -5.3125 1.21875q-2.0 0.296875 -2.84375 0.65625q-0.828125 0.359375 -1.28125 1.0625q-0.4375 0.6875 -0.4375 1.53125q0 1.3125 0.984375 2.1875q0.984375 0.859375 2.875 0.859375q1.875 0 3.34375 -0.828125q1.46875 -0.828125 2.15625 -2.25q0.515625 -1.09375 0.515625 -3.25l0 -1.1875zm21.881104 9.625l-3.015625 0l0 -26.484375l3.25 0l0 9.453125q2.0625 -2.59375 5.265625 -2.59375q1.765625 0 3.34375 0.71875q1.578125 0.71875 2.59375 2.015625q1.03125 1.28125 1.609375 3.109375q0.578125 1.828125 0.578125 3.90625q0 4.921875 -2.4375 7.625q-2.4375 2.6875 -5.859375 2.6875q-3.390625 0 -5.328125 -2.84375l0 2.40625zm-0.03125 -9.734375q0 3.453125 0.9375 4.984375q1.53125 2.515625 4.15625 2.515625q2.125 0 3.671875 -1.84375q1.5625 -1.859375 1.5625 -5.53125q0 -3.765625 -1.5 -5.546875q-1.484375 -1.796875 -3.59375 -1.796875q-2.125 0 -3.6875 1.859375q-1.546875 1.84375 -1.546875 5.359375zm17.713257 9.734375l0 -26.484375l3.265625 0l0 26.484375l-3.265625 0zm7.1681213 -9.59375q0 -5.328125 2.953125 -7.890625q2.484375 -2.140625 6.03125 -2.140625q3.96875 0 6.46875 2.59375q2.515625 2.59375 2.515625 7.171875q0 3.703125 -1.109375 5.828125q-1.109375 2.109375 -3.234375 3.296875q-2.125 1.171875 -4.640625 1.171875q-4.015625 0 -6.5 -2.578125q-2.484375 -2.59375 -2.484375 -7.453125zm3.34375 0q0 3.6875 1.59375 5.53125q1.609375 1.828125 4.046875 1.828125q2.421875 0 4.03125 -1.84375q1.609375 -1.84375 1.609375 -5.625q0 -3.5625 -1.625 -5.390625q-1.609375 -1.828125 -4.015625 -1.828125q-2.4375 0 -4.046875 1.828125q-1.59375 1.8125 -1.59375 5.5zm31.135132 2.5625l3.203125 0.421875q-0.515625 3.296875 -2.6875 5.171875q-2.15625 1.875 -5.296875 1.875q-3.9375 0 -6.328125 -2.578125q-2.390625 -2.578125 -2.390625 -7.375q0 -3.109375 1.015625 -5.4375q1.03125 -2.34375 3.140625 -3.5q2.109375 -1.171875 4.578125 -1.171875q3.125 0 5.109375 1.59375q2.0 1.578125 2.546875 4.484375l-3.15625 0.484375q-0.453125 -1.9375 -1.609375 -2.90625q-1.140625 -0.984375 -2.765625 -0.984375q-2.453125 0 -4.0 1.765625q-1.53125 1.765625 -1.53125 5.578125q0 3.859375 1.484375 5.625q1.484375 1.75 3.875 1.75q1.90625 0 3.1875 -1.171875q1.28125 -1.1875 1.625 -3.625zm6.1640625 7.03125l0 -26.484375l3.25 0l0 15.109375l7.703125 -7.8125l4.203125 0l-7.328125 7.125l8.078125 12.0625l-4.015625 0l-6.34375 -9.8125l-2.296875 2.203125l0 7.609375l-3.25 0z" fill-rule="nonzero"></path><path fill="#fff2cc" d="m440.2152 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m440.2152 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m453.62442 438.38455l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860077 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.391327 -1.828125q0 -2.421875 0.5 -3.890625q0.5 -1.46875 1.46875 -2.265625q0.984375 -0.796875 2.46875 -0.796875q1.09375 0 1.921875 0.4375q0.828125 0.4375 1.359375 1.28125q0.546875 0.828125 0.84375 2.015625q0.3125 1.1875 0.3125 3.21875q0 2.390625 -0.5 3.859375q-0.484375 1.46875 -1.46875 2.28125q-0.96875 0.796875 -2.46875 0.796875q-1.96875 0 -3.078125 -1.40625q-1.359375 -1.703125 -1.359375 -5.53125zm1.71875 0q0 3.34375 0.78125 4.453125q0.796875 1.109375 1.9375 1.109375q1.15625 0 1.9375 -1.109375q0.78125 -1.125 0.78125 -4.453125q0 -3.359375 -0.78125 -4.46875q-0.78125 -1.109375 -1.953125 -1.109375q-1.15625 0 -1.828125 0.984375q-0.875 1.234375 -0.875 4.59375z" fill-rule="nonzero"></path><path fill="#fff2cc" d="m529.6798 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m529.6798 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m543.089 438.38455l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860046 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm14.688232 4.875l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625z" fill-rule="nonzero"></path><path fill="#fff2cc" d="m619.14435 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m619.14435 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m632.5535 438.38455l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860107 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm17.172546 3.265625l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0z" fill-rule="nonzero"></path><path fill="#fff2cc" d="m708.60895 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m708.60895 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m722.0181 438.38455l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860046 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.406982 1.28125l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625z" fill-rule="nonzero"></path><path fill="#fff2cc" d="m798.0735 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m798.0735 411.24408l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m811.48267 438.38455l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.860107 2.703125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm13.750671 4.875l0 -3.25l-5.90625 0l0 -1.53125l6.21875 -8.8125l1.359375 0l0 8.8125l1.84375 0l0 1.53125l-1.84375 0l0 3.25l-1.671875 0zm0 -4.78125l0 -6.140625l-4.25 6.140625l4.25 0z" fill-rule="nonzero"></path><path fill="#ead1dc" d="m260.48032 227.8727l75.1181 0l0 40.440964l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m260.48032 227.8727l75.1181 0l0 40.440964l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m283.95062 251.4038l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.859375 3.609375l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm4.191681 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm10.879211 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110077 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm14.031982 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125z" fill-rule="nonzero"></path><path fill="#d9ead3" d="m65.75328 411.2454l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m65.75328 411.2454l75.1181 0l0 40.44095l-75.1181 0z" fill-rule="nonzero"></path><path fill="#000000" d="m85.53747 438.38586l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm10.813217 4.921875l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm7.594467 5.234375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm12.870804 -1.453125q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.078842 8.71875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.875717 -6.8125l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m298.03937 268.31366l-194.74016 142.92911" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m298.03937 268.31366l-189.90314 139.379" fill-rule="evenodd"></path><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m107.15892 406.36108l-2.6811676 4.0167236l4.6357803 -1.3535767z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m298.03937 268.31366l179.74805 142.92911" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m298.03937 268.31366l175.05176 139.19482" fill-rule="evenodd"></path><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m472.0631 408.8013l4.5800476 1.5316162l-2.5240173 -4.117279z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m298.03937 268.31366l358.6772 142.92911" fill-rule="nonzero"></path><path stroke="#595959" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m298.03937 268.31366l353.1034 140.70804" fill-rule="evenodd"></path><path fill="#595959" stroke="#595959" stroke-width="1.0" stroke-linecap="butt" d="m650.5313 410.5561l4.8271484 0.14550781l-3.604248 -3.2142944z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m106.43307 301.02625l111.37008 0l0 32.409454l-111.37008 0z" fill-rule="nonzero"></path><path fill="#000000" d="m122.51119 327.94626l-1.671875 0l0 -10.640625q-0.59375 0.578125 -1.578125 1.15625q-0.984375 0.5625 -1.765625 0.859375l0 -1.625q1.40625 -0.65625 2.453125 -1.59375q1.046875 -0.9375 1.484375 -1.8125l1.078125 0l0 13.65625zm5.016342 0l0 -1.90625l1.9062576 0l0 1.90625l-1.9062576 0zm16.28849 0l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm9.281967 -6.765625l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.4573212 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.4375 -0.671875l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.265625 -1.3125q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm12.016342 4.921875l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.34375 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094467 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m445.85303 301.02625l111.370056 0l0 32.409454l-111.370056 0z" fill-rule="nonzero"></path><path fill="#000000" d="m455.6499 324.3525l1.671875 -0.21875q0.28125 1.421875 0.96875 2.046875q0.703125 0.625 1.6875 0.625q1.1875 0 2.0 -0.8125q0.8125 -0.828125 0.8125 -2.03125q0 -1.140625 -0.765625 -1.890625q-0.75 -0.75 -1.90625 -0.75q-0.46875 0 -1.171875 0.1875l0.1875 -1.46875q0.15625 0.015625 0.265625 0.015625q1.0625 0 1.90625 -0.546875q0.859375 -0.5625 0.859375 -1.71875q0 -0.921875 -0.625 -1.515625q-0.609375 -0.609375 -1.59375 -0.609375q-0.96875 0 -1.625 0.609375q-0.640625 0.609375 -0.828125 1.84375l-1.671875 -0.296875q0.296875 -1.6875 1.375 -2.609375q1.09375 -0.921875 2.71875 -0.921875q1.109375 0 2.046875 0.484375q0.9375 0.46875 1.421875 1.296875q0.5 0.828125 0.5 1.75q0 0.890625 -0.46875 1.609375q-0.46875 0.71875 -1.40625 1.15625q1.21875 0.265625 1.875 1.15625q0.671875 0.875 0.671875 2.1875q0 1.78125 -1.296875 3.015625q-1.296875 1.234375 -3.28125 1.234375q-1.796875 0 -2.984375 -1.0625q-1.171875 -1.0625 -1.34375 -2.765625zm11.297577 3.59375l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm9.600983 0.8125l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047607 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm12.766327 4.375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.2770691 1.734375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm6.4332886 3.546875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.313232 4.875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm7.5788574 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m308.41995 146.15486l146.77164 0l0 32.40944l-146.77164 0z" fill-rule="nonzero"></path><path fill="#000000" d="m326.98245 171.46548l0 1.609375l-8.984375 0q-0.015625 -0.609375 0.1875 -1.15625q0.34375 -0.921875 1.09375 -1.8125q0.765625 -0.890625 2.1875 -2.0625q2.21875 -1.8125 3.0 -2.875q0.78125 -1.0625 0.78125 -2.015625q0 -0.984375 -0.71875 -1.671875q-0.703125 -0.6875 -1.84375 -0.6875q-1.203125 0 -1.9375 0.734375q-0.71875 0.71875 -0.71875 2.0l-1.71875 -0.171875q0.171875 -1.921875 1.328125 -2.921875q1.15625 -1.015625 3.09375 -1.015625q1.953125 0 3.09375 1.09375q1.140625 1.078125 1.140625 2.6875q0 0.8125 -0.34375 1.609375q-0.328125 0.78125 -1.109375 1.65625q-0.765625 0.859375 -2.5625 2.390625q-1.5 1.265625 -1.9375 1.71875q-0.421875 0.4375 -0.703125 0.890625l6.671875 0zm2.531952 1.609375l0 -1.90625l1.90625 0l0 1.90625l-1.90625 0zm9.882233 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.978302 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.766327 0l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm16.016357 1.75l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.235077 5.875l0 -1.359375l6.265625 -7.1875q-1.0625 0.046875 -1.875 0.046875l-4.015625 0l0 -1.359375l8.046875 0l0 1.109375l-5.34375 6.25l-1.015625 1.140625q1.109375 -0.078125 2.09375 -0.078125l4.5625 0l0 1.4375l-8.71875 0zm12.9375 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm5.96875 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735107 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.250702 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375z" fill-rule="nonzero"></path></g></svg>
+
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 960.0 540.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="g150061aa58_0_20.0"><path d="m0 0l960.0 0l0 540.0l-960.0 0l0 -540.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#g150061aa58_0_20.0)"><path fill="#ffffff" d="m0 0l960.0 0l0 540.0l-960.0 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.72441 46.721786l894.55115 0l0 60.125984l-894.55115 0z" fill-rule="nonzero"></path><path fill="#000000" d="m44.63066 91.56178l0 -26.484375l11.75 0q3.53125 0 5.375 0.71875q1.84375 0.703125 2.9375 2.515625q1.109375 1.8125 1.109375 3.984375q0 2.828125 -1.828125 4.765625q-1.8125 1.921875 -5.625 2.453125q1.390625 0.671875 2.109375 1.3125q1.53125 1.40625 2.90625 3.53125l4.609375 7.203125l-4.40625 0l-3.5 -5.515625q-1.546875 -2.375 -2.546875 -3.640625q-0.984375 -1.265625 -1.765625 -1.765625q-0.78125 -0.515625 -1.59375 -0.71875q-0.609375 -0.125 -1.953125 -0.125l-4.078125 0l0 11.765625l-3.5 0zm3.5 -14.796875l7.546875 0q2.390625 0 3.75 -0.5q1.359375 -0.5 2.0625 -1.578125q0.703125 -1.09375 0.703125 -2.390625q0 -1.875 -1.375 -3.078125q-1.359375 -1.21875 -4.296875 -1.21875l-8.390625 0l0 8.765625zm36.12906 8.625l3.359375 0.40625q-0.796875 2.953125 -2.953125 4.578125q-2.140625 1.625 -5.484375 1.625q-4.21875 0 -6.6875 -2.59375q-2.453125 -2.59375 -2.453125 -7.28125q0 -4.828125 2.484375 -7.5q2.5 -2.6875 6.46875 -2.6875q3.859375 0 6.296875 2.625q2.4375 2.625 2.4375 7.375q0 0.28125 -0.015625 0.859375l-14.3125 0q0.171875 3.171875 1.78125 4.859375q1.609375 1.671875 4.015625 1.671875q1.78125 0 3.046875 -0.9375q1.265625 -0.953125 2.015625 -3.0zm-10.6875 -5.265625l10.71875 0q-0.21875 -2.421875 -1.234375 -3.625q-1.546875 -1.890625 -4.015625 -1.890625q-2.25 0 -3.78125 1.5q-1.515625 1.5 -1.6875 4.015625zm18.307007 11.4375l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm33.213257 0l0 -2.421875q-1.828125 2.859375 -5.375 2.859375q-2.28125 0 -4.21875 -1.265625q-1.921875 -1.265625 -2.984375 -3.53125q-1.046875 -2.265625 -1.046875 -5.21875q0 -2.875 0.953125 -5.203125q0.96875 -2.34375 2.875 -3.59375q1.921875 -1.25 4.28125 -1.25q1.734375 0 3.09375 0.734375q1.359375 0.734375 2.203125 1.90625l0 -9.5l3.234375 0l0 26.484375l-3.015625 0zm-10.28125 -9.578125q0 3.6875 1.546875 5.515625q1.5625 1.828125 3.671875 1.828125q2.125 0 3.609375 -1.75q1.5 -1.75 1.5 -5.3125q0 -3.953125 -1.515625 -5.78125q-1.515625 -1.84375 -3.734375 -1.84375q-2.171875 0 -3.625 1.765625q-1.453125 1.765625 -1.453125 5.578125zm31.728882 3.40625l3.359375 0.40625q-0.796875 2.953125 -2.953125 4.578125q-2.140625 1.625 -5.484375 1.625q-4.21875 0 -6.6875 -2.59375q-2.453125 -2.59375 -2.453125 -7.28125q0 -4.828125 2.484375 -7.5q2.5 -2.6875 6.46875 -2.6875q3.859375 0 6.296875 2.625q2.4375 2.625 2.4375 7.375q0 0.28125 -0.015625 0.859375l-14.3125 0q0.171875 3.171875 1.78125 4.859375q1.609375 1.671875 4.015625 1.671875q1.78125 0 3.046875 -0.9375q1.265625 -0.953125 2.015625 -3.0zm-10.6875 -5.265625l10.71875 0q-0.21875 -2.421875 -1.234375 -3.625q-1.546875 -1.890625 -4.015625 -1.890625q-2.25 0 -3.78125 1.5q-1.515625 1.5 -1.6875 4.015625zm16.588257 11.4375l0 -2.640625l12.21875 -14.015625q-2.078125 0.109375 -3.671875 0.109375l-7.8125 0l0 -2.640625l15.671875 0l0 2.15625l-10.390625 12.171875l-2.0 2.21875q2.1875 -0.15625 4.09375 -0.15625l8.875 0l0 2.796875l-16.984375 0zm25.710938 0l-7.296875 -19.1875l3.4375 0l4.109375 11.484375q0.671875 1.875 1.234375 3.875q0.4375 -1.515625 1.203125 -3.65625l4.265625 -11.703125l3.34375 0l-7.265625 19.1875l-3.03125 0zm12.1328125 -9.59375q0 -5.328125 2.953125 -7.890625q2.484375 -2.140625 6.03125 -2.140625q3.96875 0 6.46875 2.59375q2.515625 2.59375 2.515625 7.171875q0 3.703125 -1.109375 5.828125q-1.109375 2.109375 -3.234375 3.296875q-2.125 1.171875 -4.640625 1.171875q-4.015625 0 -6.5 -2.578125q-2.484375 -2.59375 -2.484375 -7.453125zm3.34375 0q0 3.6875 1.59375 5.53125q1.609375 1.828125 4.046875 1.828125q2.421875 0 4.03125 -1.84375q1.609375 -1.84375 1.609375 -5.625q0 -3.5625 -1.625 -5.390625q-1.609375 -1.828125 -4.015625 -1.828125q-2.4375 0 -4.046875 1.828125q-1.59375 1.8125 -1.59375 5.5zm31.197632 9.59375l0 -2.8125q-2.25 3.25 -6.09375 3.25q-1.6875 0 -3.171875 -0.65625q-1.46875 -0.65625 -2.1875 -1.640625q-0.703125 -0.984375 -1.0 -2.40625q-0.203125 -0.953125 -0.203125 -3.03125l0 -11.890625l3.265625 0l0 10.640625q0 2.546875 0.1875 3.4375q0.3125 1.28125 1.296875 2.015625q1.0 0.734375 2.46875 0.734375q1.453125 0 2.734375 -0.75q1.296875 -0.75 1.828125 -2.046875q0.53125 -1.296875 0.53125 -3.75l0 -10.28125l3.25 0l0 19.1875l-2.90625 0zm6.885132 -5.734375l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625zm30.331894 5.734375l0 -26.484375l3.25 0l0 9.5q2.28125 -2.640625 5.75 -2.640625q2.125 0 3.703125 0.84375q1.578125 0.84375 2.25 2.328125q0.671875 1.46875 0.671875 4.296875l0 12.15625l-3.25 0l0 -12.15625q0 -2.4375 -1.0625 -3.546875q-1.046875 -1.109375 -2.984375 -1.109375q-1.4375 0 -2.71875 0.75q-1.265625 0.734375 -1.8125 2.03125q-0.546875 1.28125 -0.546875 3.53125l0 10.5l-3.25 0zm33.275726 -2.359375q-1.796875 1.53125 -3.46875 2.171875q-1.671875 0.625 -3.5937195 0.625q-3.15625 0 -4.859375 -1.546875q-1.6875 -1.546875 -1.6875 -3.953125q0 -1.40625 0.640625 -2.5625q0.640625 -1.171875 1.671875 -1.875q1.046875 -0.703125 2.34375 -1.0625q0.953125 -0.265625 2.8905945 -0.5q3.9375 -0.46875 5.796875 -1.109375q0.015625 -0.671875 0.015625 -0.859375q0 -1.984375 -0.921875 -2.796875q-1.25 -1.09375 -3.703125 -1.09375q-2.2968445 0 -3.3905945 0.796875q-1.09375 0.796875 -1.609375 2.84375l-3.1875 -0.4375q0.4375 -2.03125 1.421875 -3.28125q1.0 -1.265625 2.875 -1.9375q1.890625 -0.6875 4.3593445 -0.6875q2.46875 0 4.0 0.578125q1.53125 0.578125 2.25 1.453125q0.734375 0.875 1.015625 2.21875q0.15625 0.828125 0.15625 3.0l0 4.328125q0 4.546875 0.203125 5.75q0.21875 1.1875 0.828125 2.296875l-3.390625 0q-0.5 -1.015625 -0.65625 -2.359375zm-0.265625 -7.265625q-1.765625 0.71875 -5.3125 1.21875q-1.9999695 0.296875 -2.8437195 0.65625q-0.828125 0.359375 -1.28125 1.0625q-0.4375 0.6875 -0.4375 1.53125q0 1.3125 0.984375 2.1875q0.984375 0.859375 2.8749695 0.859375q1.875 0 3.34375 -0.828125q1.46875 -0.828125 2.15625 -2.25q0.515625 -1.09375 0.515625 -3.25l0 -1.1875zm7.213257 3.890625l3.21875 -0.5q0.265625 1.9375 1.5 2.96875q1.234375 1.03125 3.46875 1.03125q2.234375 0 3.3125 -0.90625q1.09375 -0.921875 1.09375 -2.15625q0 -1.09375 -0.96875 -1.734375q-0.65625 -0.4375 -3.3125 -1.09375q-3.578125 -0.90625 -4.96875 -1.5625q-1.375 -0.671875 -2.09375 -1.828125q-0.703125 -1.171875 -0.703125 -2.578125q0 -1.28125 0.578125 -2.375q0.59375 -1.09375 1.59375 -1.8125q0.765625 -0.5625 2.078125 -0.953125q1.3125 -0.390625 2.8125 -0.390625q2.25 0 3.953125 0.65625q1.71875 0.65625 2.53125 1.765625q0.8125 1.109375 1.109375 2.96875l-3.171875 0.4375q-0.21875 -1.484375 -1.265625 -2.3125q-1.03125 -0.84375 -2.921875 -0.84375q-2.25 0 -3.203125 0.75q-0.953125 0.734375 -0.953125 1.734375q0 0.625 0.390625 1.140625q0.40625 0.515625 1.25 0.859375q0.484375 0.1875 2.875 0.828125q3.453125 0.921875 4.8125 1.515625q1.359375 0.578125 2.140625 1.703125q0.78125 1.125 0.78125 2.78125q0 1.625 -0.953125 3.0625q-0.953125 1.4375 -2.75 2.234375q-1.78125 0.78125 -4.03125 0.78125q-3.75 0 -5.703125 -1.546875q-1.953125 -1.5625 -2.5 -4.625zm19.960938 5.734375l0 -26.484375l3.25 0l0 9.5q2.28125 -2.640625 5.75 -2.640625q2.125 0 3.703125 0.84375q1.578125 0.84375 2.25 2.328125q0.671875 1.46875 0.671875 4.296875l0 12.15625l-3.25 0l0 -12.15625q0 -2.4375 -1.0625 -3.546875q-1.046875 -1.109375 -2.984375 -1.109375q-1.4375 0 -2.71875 0.75q-1.265625 0.734375 -1.8125 2.03125q-0.546875 1.28125 -0.546875 3.53125l0 10.5l-3.25 0zm20.775757 -22.75l0 -3.734375l3.25 0l0 3.734375l-3.25 0zm0 22.75l0 -19.1875l3.25 0l0 19.1875l-3.25 0zm8.277496 0l0 -19.1875l2.921875 0l0 2.734375q2.125 -3.171875 6.109375 -3.171875q1.734375 0 3.1875 0.625q1.453125 0.625 2.171875 1.640625q0.734375 1.015625 1.015625 2.40625q0.1875 0.890625 0.1875 3.15625l0 11.796875l-3.25 0l0 -11.671875q0 -1.984375 -0.390625 -2.96875q-0.375 -0.984375 -1.34375 -1.5625q-0.953125 -0.59375 -2.265625 -0.59375q-2.078125 0 -3.59375 1.3125q-1.5 1.3125 -1.5 5.0l0 10.484375l-3.25 0zm20.166382 1.59375l3.15625 0.46875q0.203125 1.453125 1.109375 2.125q1.203125 0.90625 3.296875 0.90625q2.265625 0 3.484375 -0.90625q1.234375 -0.90625 1.671875 -2.53125q0.25 -0.984375 0.234375 -4.171875q-2.125 2.515625 -5.3125 2.515625q-3.953125 0 -6.125 -2.84375q-2.171875 -2.859375 -2.171875 -6.859375q0 -2.75 1.0 -5.0625q1.0 -2.328125 2.875 -3.59375q1.890625 -1.265625 4.4375 -1.265625q3.40625 0 5.609375 2.75l0 -2.3125l3.0 0l0 16.578125q0 4.484375 -0.921875 6.359375q-0.90625 1.875 -2.890625 2.953125q-1.96875 1.078125 -4.859375 1.078125q-3.4375 0 -5.5625 -1.546875q-2.109375 -1.53125 -2.03125 -4.640625zm2.6875 -11.53125q0 3.78125 1.5 5.515625q1.5 1.734375 3.765625 1.734375q2.234375 0 3.75 -1.71875q1.515625 -1.734375 1.515625 -5.421875q0 -3.515625 -1.5625 -5.296875q-1.5625 -1.796875 -3.765625 -1.796875q-2.171875 0 -3.6875 1.765625q-1.515625 1.75 -1.515625 5.21875z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m32.72441 467.15222l894.55115 0l0 54.519714l-894.55115 0z" fill-rule="nonzero"></path><path fill="#595959" d="m167.41017 499.19223l-3.796875 -12.453125l2.171875 0l1.984375 7.1875l0.734375 2.671875q0.046875 -0.203125 0.640625 -2.5625l1.984375 -7.296875l2.171875 0l1.859375 7.21875l0.625 2.390625l0.71875 -2.40625l2.125 -7.203125l2.046875 0l-3.890625 12.453125l-2.1875 0l-1.984375 -7.453125l-0.46875 -2.125l-2.53125 9.578125l-2.203125 0zm23.566406 -4.015625l2.171875 0.28125q-0.515625 1.90625 -1.90625 2.96875q-1.390625 1.046875 -3.5625 1.046875q-2.734375 0 -4.34375 -1.671875q-1.59375 -1.6875 -1.59375 -4.734375q0 -3.140625 1.609375 -4.875q1.625 -1.734375 4.203125 -1.734375q2.5 0 4.078125 1.703125q1.59375 1.703125 1.59375 4.78125q0 0.1875 -0.015625 0.5625l-9.28125 0q0.109375 2.046875 1.15625 3.140625q1.046875 1.09375 2.609375 1.09375q1.15625 0 1.96875 -0.609375q0.828125 -0.609375 1.3125 -1.953125zm-6.9375 -3.40625l6.953125 0q-0.140625 -1.5625 -0.796875 -2.359375q-1.0 -1.21875 -2.609375 -1.21875q-1.453125 0 -2.453125 0.984375q-0.984375 0.96875 -1.09375 2.59375zm11.769531 -7.328125l0 -2.4375l2.109375 0l0 2.4375l-2.109375 0zm0 14.75l0 -12.453125l2.109375 0l0 12.453125l-2.109375 0zm4.9414062 1.03125l2.046875 0.3125q0.125 0.9375 0.71875 1.375q0.78125 0.59375 2.140625 0.59375q1.46875 0 2.265625 -0.59375q0.796875 -0.578125 1.078125 -1.640625q0.15625 -0.640625 0.140625 -2.703125q-1.375 1.625 -3.4375 1.625q-2.5625 0 -3.96875 -1.84375q-1.40625 -1.859375 -1.40625 -4.453125q0 -1.78125 0.640625 -3.28125q0.640625 -1.515625 1.859375 -2.328125q1.234375 -0.828125 2.890625 -0.828125q2.203125 0 3.625 1.78125l0 -1.5l1.953125 0l0 10.765625q0 2.90625 -0.59375 4.109375q-0.59375 1.21875 -1.875 1.921875q-1.28125 0.703125 -3.15625 0.703125q-2.234375 0 -3.609375 -1.0q-1.359375 -1.0 -1.3125 -3.015625zm1.734375 -7.484375q0 2.453125 0.96875 3.578125q0.984375 1.125 2.453125 1.125q1.453125 0 2.4375 -1.109375q0.984375 -1.125 0.984375 -3.515625q0 -2.28125 -1.015625 -3.4375q-1.015625 -1.171875 -2.453125 -1.171875q-1.40625 0 -2.390625 1.140625q-0.984375 1.140625 -0.984375 3.390625zm11.988281 6.453125l0 -17.1875l2.109375 0l0 6.171875q1.484375 -1.71875 3.734375 -1.71875q1.375 0 2.390625 0.546875q1.03125 0.546875 1.46875 1.515625q0.4375 0.953125 0.4375 2.78125l0 7.890625l-2.109375 0l0 -7.890625q0 -1.578125 -0.6875 -2.296875q-0.6875 -0.71875 -1.9375 -0.71875q-0.9375 0 -1.765625 0.484375q-0.828125 0.484375 -1.1875 1.3125q-0.34375 0.828125 -0.34375 2.296875l0 6.8125l-2.109375 0zm17.957031 -1.890625l0.3125 1.859375q-0.890625 0.203125 -1.59375 0.203125q-1.15625 0 -1.796875 -0.359375q-0.625 -0.375 -0.890625 -0.96875q-0.25 -0.59375 -0.25 -2.484375l0 -7.171875l-1.546875 0l0 -1.640625l1.546875 0l0 -3.078125l2.09375 -1.265625l0 4.34375l2.125 0l0 1.640625l-2.125 0l0 7.28125q0 0.90625 0.109375 1.171875q0.125 0.25 0.375 0.40625q0.25 0.140625 0.71875 0.140625q0.34375 0 0.921875 -0.078125zm19.835938 -8.21875l-11.34375 0l0 -1.96875l11.34375 0l0 1.96875zm0 5.21875l-11.34375 0l0 -1.96875l11.34375 0l0 1.96875zm9.5742035 4.890625l0 -17.1875l2.109375 0l0 6.171875q1.484375 -1.71875 3.734375 -1.71875q1.375 0 2.390625 0.546875q1.03125 0.546875 1.46875 1.515625q0.4375 0.953125 0.4375 2.78125l0 7.890625l-2.109375 0l0 -7.890625q0 -1.578125 -0.6875 -2.296875q-0.6875 -0.71875 -1.9375 -0.71875q-0.9375 0 -1.765625 0.484375q-0.828125 0.484375 -1.1875 1.3125q-0.34375 0.828125 -0.34375 2.296875l0 6.8125l-2.109375 0zm12.566406 -6.21875q0 -3.46875 1.921875 -5.125q1.609375 -1.390625 3.921875 -1.390625q2.5625 0 4.1875 1.6875q1.625 1.6875 1.625 4.640625q0 2.40625 -0.71875 3.78125q-0.71875 1.375 -2.09375 2.140625q-1.375 0.765625 -3.0 0.765625q-2.625 0 -4.234375 -1.671875q-1.609375 -1.6875 -1.609375 -4.828125zm2.171875 0q0 2.390625 1.03125 3.578125q1.046875 1.1875 2.640625 1.1875q1.5625 0 2.609375 -1.1875q1.046875 -1.203125 1.046875 -3.65625q0 -2.3125 -1.0625 -3.5q-1.046875 -1.1875 -2.59375 -1.1875q-1.59375 0 -2.640625 1.1875q-1.03125 1.1875 -1.03125 3.578125zm14.253906 6.21875l-3.796875 -12.453125l2.171875 0l1.984375 7.1875l0.734375 2.671875q0.046875 -0.203125 0.640625 -2.5625l1.984375 -7.296875l2.171875 0l1.859375 7.21875l0.625 2.390625l0.71875 -2.40625l2.125 -7.203125l2.046875 0l-3.890625 12.453125l-2.1875 0l-1.984375 -7.453125l-0.46875 -2.125l-2.53125 9.578125l-2.203125 0zm29.828125 -1.53125q-1.171875 0.984375 -2.265625 1.40625q-1.078125 0.40625 -2.3125 0.40625q-2.046875 0 -3.15625 -1.0q-1.09375 -1.0 -1.09375 -2.5625q0 -0.921875 0.40625 -1.671875q0.421875 -0.75 1.09375 -1.203125q0.671875 -0.46875 1.515625 -0.703125q0.625 -0.15625 1.875 -0.3125q2.5625 -0.3125 3.765625 -0.734375q0.015625 -0.421875 0.015625 -0.546875q0 -1.28125 -0.609375 -1.8125q-0.796875 -0.71875 -2.390625 -0.71875q-1.5 0 -2.203125 0.53125q-0.703125 0.515625 -1.046875 1.84375l-2.0625 -0.28125q0.28125 -1.328125 0.921875 -2.140625q0.640625 -0.8125 1.859375 -1.25q1.21875 -0.453125 2.828125 -0.453125q1.59375 0 2.59375 0.375q1.0 0.375 1.46875 0.953125q0.46875 0.5625 0.65625 1.4375q0.09375 0.53125 0.09375 1.9375l0 2.8125q0 2.9375 0.140625 3.71875q0.140625 0.78125 0.53125 1.5l-2.203125 0q-0.328125 -0.65625 -0.421875 -1.53125zm-0.171875 -4.71875q-1.15625 0.46875 -3.453125 0.796875q-1.296875 0.1875 -1.84375 0.421875q-0.53125 0.234375 -0.828125 0.6875q-0.28125 0.453125 -0.28125 1.0q0 0.84375 0.625 1.40625q0.640625 0.5625 1.875 0.5625q1.21875 0 2.171875 -0.53125q0.953125 -0.53125 1.390625 -1.453125q0.34375 -0.71875 0.34375 -2.109375l0 -0.78125zm5.3945312 11.015625l0 -17.21875l1.921875 0l0 1.625q0.6875 -0.953125 1.53125 -1.421875q0.859375 -0.484375 2.078125 -0.484375q1.59375 0 2.8125 0.828125q1.21875 0.8125 1.84375 2.3125q0.625 1.5 0.625 3.28125q0 1.90625 -0.6875 3.4375q-0.6875 1.53125 -2.0 2.34375q-1.296875 0.8125 -2.734375 0.8125q-1.0625 0 -1.90625 -0.4375q-0.828125 -0.453125 -1.375 -1.140625l0 6.0625l-2.109375 0zm1.921875 -10.921875q0 2.40625 0.96875 3.5625q0.96875 1.140625 2.359375 1.140625q1.40625 0 2.40625 -1.1875q1.0 -1.1875 1.0 -3.6875q0 -2.375 -0.984375 -3.5625q-0.96875 -1.1875 -2.328125 -1.1875q-1.359375 0 -2.390625 1.265625q-1.03125 1.25 -1.03125 3.65625zm11.425781 10.921875l0 -17.21875l1.921875 0l0 1.625q0.6875 -0.953125 1.53125 -1.421875q0.859375 -0.484375 2.078125 -0.484375q1.59375 0 2.8125 0.828125q1.21875 0.8125 1.84375 2.3125q0.625 1.5 0.625 3.28125q0 1.90625 -0.6875 3.4375q-0.6875 1.53125 -2.0 2.34375q-1.296875 0.8125 -2.734375 0.8125q-1.0625 0 -1.90625 -0.4375q-0.828125 -0.453125 -1.375 -1.140625l0 6.0625l-2.109375 0zm1.921875 -10.921875q0 2.40625 0.96875 3.5625q0.96875 1.140625 2.359375 1.140625q1.40625 0 2.40625 -1.1875q1.0 -1.1875 1.0 -3.6875q0 -2.375 -0.984375 -3.5625q-0.96875 -1.1875 -2.328125 -1.1875q-1.359375 0 -2.390625 1.265625q-1.03125 1.25 -1.03125 3.65625zm11.410156 6.15625l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm7.2265625 -6.21875q0 -3.46875 1.921875 -5.125q1.609375 -1.390625 3.921875 -1.390625q2.5625 0 4.1875 1.6875q1.625 1.6875 1.625 4.640625q0 2.40625 -0.71875 3.78125q-0.71875 1.375 -2.09375 2.140625q-1.375 0.765625 -3.0 0.765625q-2.625 0 -4.234375 -1.671875q-1.609375 -1.6875 -1.609375 -4.828125zm2.171875 0q0 2.390625 1.03125 3.578125q1.046875 1.1875 2.640625 1.1875q1.5625 0 2.609375 -1.1875q1.046875 -1.203125 1.046875 -3.65625q0 -2.3125 -1.0625 -3.5q-1.046875 -1.1875 -2.59375 -1.1875q-1.59375 0 -2.640625 1.1875q-1.03125 1.1875 -1.03125 3.578125zm11.957031 10.984375l0 -17.21875l1.921875 0l0 1.625q0.6875 -0.953125 1.53125 -1.421875q0.859375 -0.484375 2.078125 -0.484375q1.59375 0 2.8125 0.828125q1.21875 0.8125 1.84375 2.3125q0.625 1.5 0.625 3.28125q0 1.90625 -0.6875 3.4375q-0.6875 1.53125 -2.0 2.34375q-1.296875 0.8125 -2.734375 0.8125q-1.0625 0 -1.90625 -0.4375q-0.828125 -0.453125 -1.375 -1.140625l0 6.0625l-2.109375 0zm1.921875 -10.921875q0 2.40625 0.96875 3.5625q0.96875 1.140625 2.359375 1.140625q1.40625 0 2.40625 -1.1875q1.0 -1.1875 1.0 -3.6875q0 -2.375 -0.984375 -3.5625q-0.96875 -1.1875 -2.328125 -1.1875q-1.359375 0 -2.390625 1.265625q-1.03125 1.25 -1.03125 3.65625zm11.410156 6.15625l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm8.0234375 -14.75l0 -2.4375l2.109375 0l0 2.4375l-2.109375 0zm0 14.75l0 -12.453125l2.109375 0l0 12.453125l-2.109375 0zm13.441406 -1.53125q-1.171875 0.984375 -2.265625 1.40625q-1.078125 0.40625 -2.3125 0.40625q-2.046875 0 -3.15625 -1.0q-1.09375 -1.0 -1.09375 -2.5625q0 -0.921875 0.40625 -1.671875q0.421875 -0.75 1.09375 -1.203125q0.671875 -0.46875 1.515625 -0.703125q0.625 -0.15625 1.875 -0.3125q2.5625 -0.3125 3.765625 -0.734375q0.015625 -0.421875 0.015625 -0.546875q0 -1.28125 -0.609375 -1.8125q-0.796875 -0.71875 -2.390625 -0.71875q-1.5 0 -2.203125 0.53125q-0.703125 0.515625 -1.046875 1.84375l-2.0625 -0.28125q0.28125 -1.328125 0.921875 -2.140625q0.640625 -0.8125 1.859375 -1.25q1.21875 -0.453125 2.828125 -0.453125q1.59375 0 2.59375 0.375q1.0 0.375 1.46875 0.953125q0.46875 0.5625 0.65625 1.4375q0.09375 0.53125 0.09375 1.9375l0 2.8125q0 2.9375 0.140625 3.71875q0.140625 0.78125 0.53125 1.5l-2.203125 0q-0.328125 -0.65625 -0.421875 -1.53125zm-0.171875 -4.71875q-1.15625 0.46875 -3.453125 0.796875q-1.296875 0.1875 -1.84375 0.421875q-0.53125 0.234375 -0.828125 0.6875q-0.28125 0.453125 -0.28125 1.0q0 0.84375 0.625 1.40625q0.640625 0.5625 1.875 0.5625q1.21875 0 2.171875 -0.53125q0.953125 -0.53125 1.390625 -1.453125q0.34375 -0.71875 0.34375 -2.109375l0 -0.78125zm10.003906 4.359375l0.3125 1.859375q-0.890625 0.203125 -1.59375 0.203125q-1.15625 0 -1.796875 -0.359375q-0.625 -0.375 -0.890625 -0.96875q-0.25 -0.59375 -0.25 -2.484375l0 -7.171875l-1.546875 0l0 -1.640625l1.546875 0l0 -3.078125l2.09375 -1.265625l0 4.34375l2.125 0l0 1.640625l-2.125 0l0 7.28125q0 0.90625 0.109375 1.171875q0.125 0.25 0.375 0.40625q0.25 0.140625 0.71875 0.140625q0.34375 0 0.921875 -0.078125zm10.589844 -2.125l2.171875 0.28125q-0.515625 1.90625 -1.90625 2.96875q-1.390625 1.046875 -3.5625 1.046875q-2.734375 0 -4.34375 -1.671875q-1.59375 -1.6875 -1.59375 -4.734375q0 -3.140625 1.609375 -4.875q1.625 -1.734375 4.203125 -1.734375q2.5 0 4.078125 1.703125q1.59375 1.703125 1.59375 4.78125q0 0.1875 -0.015625 0.5625l-9.28125 0q0.109375 2.046875 1.15625 3.140625q1.046875 1.09375 2.609375 1.09375q1.15625 0 1.96875 -0.609375q0.828125 -0.609375 1.3125 -1.953125zm-6.9375 -3.40625l6.953125 0q-0.140625 -1.5625 -0.796875 -2.359375q-1.0 -1.21875 -2.609375 -1.21875q-1.453125 0 -2.453125 0.984375q-0.984375 0.96875 -1.09375 2.59375zm18.4375 -7.328125l0 -2.4375l2.109375 0l0 2.4375l-2.109375 0zm0 14.75l0 -12.453125l2.109375 0l0 12.453125l-2.109375 0zm4.4726562 -3.71875l2.09375 -0.328125q0.171875 1.25 0.96875 1.921875q0.8125 0.671875 2.25 0.671875q1.453125 0 2.15625 -0.59375q0.703125 -0.59375 0.703125 -1.390625q0 -0.71875 -0.625 -1.125q-0.421875 -0.28125 -2.15625 -0.71875q-2.3125 -0.578125 -3.21875 -1.0q-0.890625 -0.4375 -1.359375 -1.1875q-0.453125 -0.765625 -0.453125 -1.671875q0 -0.828125 0.375 -1.53125q0.390625 -0.71875 1.046875 -1.1875q0.484375 -0.359375 1.328125 -0.609375q0.859375 -0.265625 1.828125 -0.265625q1.46875 0 2.578125 0.421875q1.109375 0.421875 1.625 1.15625q0.53125 0.71875 0.734375 1.921875l-2.0625 0.28125q-0.140625 -0.96875 -0.8125 -1.5q-0.671875 -0.546875 -1.90625 -0.546875q-1.453125 0 -2.078125 0.484375q-0.625 0.484375 -0.625 1.125q0 0.40625 0.265625 0.734375q0.25 0.34375 0.8125 0.5625q0.3125 0.125 1.859375 0.546875q2.234375 0.59375 3.109375 0.984375q0.890625 0.375 1.390625 1.109375q0.515625 0.71875 0.515625 1.796875q0 1.046875 -0.625 1.984375q-0.609375 0.9375 -1.765625 1.453125q-1.15625 0.5 -2.625 0.5q-2.421875 0 -3.703125 -1.0q-1.265625 -1.015625 -1.625 -3.0zm18.667969 0l2.09375 -0.328125q0.171875 1.25 0.96875 1.921875q0.8125 0.671875 2.25 0.671875q1.453125 0 2.15625 -0.59375q0.703125 -0.59375 0.703125 -1.390625q0 -0.71875 -0.625 -1.125q-0.421875 -0.28125 -2.15625 -0.71875q-2.3125 -0.578125 -3.21875 -1.0q-0.890625 -0.4375 -1.359375 -1.1875q-0.453125 -0.765625 -0.453125 -1.671875q0 -0.828125 0.375 -1.53125q0.390625 -0.71875 1.046875 -1.1875q0.484375 -0.359375 1.328125 -0.609375q0.859375 -0.265625 1.828125 -0.265625q1.46875 0 2.578125 0.421875q1.109375 0.421875 1.625 1.15625q0.53125 0.71875 0.734375 1.921875l-2.0625 0.28125q-0.140625 -0.96875 -0.8125 -1.5q-0.671875 -0.546875 -1.90625 -0.546875q-1.453125 0 -2.078125 0.484375q-0.625 0.484375 -0.625 1.125q0 0.40625 0.265625 0.734375q0.25 0.34375 0.8125 0.5625q0.3125 0.125 1.859375 0.546875q2.234375 0.59375 3.109375 0.984375q0.890625 0.375 1.390625 1.109375q0.515625 0.71875 0.515625 1.796875q0 1.046875 -0.625 1.984375q-0.609375 0.9375 -1.765625 1.453125q-1.15625 0.5 -2.625 0.5q-2.421875 0 -3.703125 -1.0q-1.265625 -1.015625 -1.625 -3.0zm21.375 -0.296875l2.171875 0.28125q-0.515625 1.90625 -1.90625 2.96875q-1.390625 1.046875 -3.5625 1.046875q-2.734375 0 -4.34375 -1.671875q-1.59375 -1.6875 -1.59375 -4.734375q0 -3.140625 1.609375 -4.875q1.625 -1.734375 4.203125 -1.734375q2.5 0 4.078125 1.703125q1.59375 1.703125 1.59375 4.78125q0 0.1875 -0.015625 0.5625l-9.28125 0q0.109375 2.046875 1.15625 3.140625q1.046875 1.09375 2.609375 1.09375q1.15625 0 1.96875 -0.609375q0.828125 -0.609375 1.3125 -1.953125zm-6.9375 -3.40625l6.953125 0q-0.140625 -1.5625 -0.796875 -2.359375q-1.0 -1.21875 -2.609375 -1.21875q-1.453125 0 -2.453125 0.984375q-0.984375 0.96875 -1.09375 2.59375zm11.738281 7.421875l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm11.4765625 0l-4.734375 -12.453125l2.21875 0l2.671875 7.453125q0.4375 1.21875 0.796875 2.515625q0.28125 -0.984375 0.78125 -2.375l2.765625 -7.59375l2.171875 0l-4.703125 12.453125l-1.96875 0zm17.0625 -4.015625l2.171875 0.28125q-0.515625 1.90625 -1.90625 2.96875q-1.390625 1.046875 -3.5625 1.046875q-2.734375 0 -4.34375 -1.671875q-1.59375 -1.6875 -1.59375 -4.734375q0 -3.140625 1.609375 -4.875q1.625 -1.734375 4.203125 -1.734375q2.5 0 4.078125 1.703125q1.59375 1.703125 1.59375 4.78125q0 0.1875 -0.015625 0.5625l-9.28125 0q0.109375 2.046875 1.15625 3.140625q1.046875 1.09375 2.609375 1.09375q1.15625 0 1.96875 -0.609375q0.828125 -0.609375 1.3125 -1.953125zm-6.9375 -3.40625l6.953125 0q-0.140625 -1.5625 -0.796875 -2.359375q-1.0 -1.21875 -2.609375 -1.21875q-1.453125 0 -2.453125 0.984375q-0.984375 0.96875 -1.09375 2.59375zm11.738281 7.421875l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm16.332031 -14.296875l0 2.453125l-2.265625 0l0 -1.9375q0 -1.578125 0.375 -2.28125q0.5 -0.9375 1.5625 -1.40625l0.515625 0.8125q-0.640625 0.265625 -0.953125 0.8125q-0.296875 0.53125 -0.328125 1.546875l1.09375 0zm3.640625 0l0 2.453125l-2.265625 0l0 -1.9375q0 -1.578125 0.375 -2.28125q0.484375 -0.9375 1.5625 -1.40625l0.515625 0.8125q-0.65625 0.265625 -0.96875 0.8125q-0.296875 0.53125 -0.328125 1.546875l1.109375 0zm2.1953735 8.78125l2.140625 -0.1875q0.15625 1.28125 0.703125 2.109375q0.5625 0.828125 1.734375 1.34375q1.171875 0.5 2.640625 0.5q1.296875 0 2.296875 -0.375q1.0 -0.390625 1.484375 -1.0625q0.484375 -0.6875 0.484375 -1.484375q0 -0.796875 -0.46875 -1.40625q-0.46875 -0.609375 -1.546875 -1.015625q-0.6875 -0.265625 -3.0625 -0.828125q-2.359375 -0.578125 -3.3125 -1.078125q-1.234375 -0.640625 -1.84375 -1.59375q-0.59375 -0.96875 -0.59375 -2.140625q0 -1.3125 0.734375 -2.4375q0.75 -1.125 2.15625 -1.703125q1.421875 -0.59375 3.15625 -0.59375q1.90625 0 3.359375 0.609375q1.46875 0.609375 2.25 1.8125q0.796875 1.1875 0.84375 2.703125l-2.171875 0.171875q-0.171875 -1.640625 -1.1875 -2.46875q-1.015625 -0.828125 -3.0 -0.828125q-2.0625 0 -3.015625 0.765625q-0.9375 0.75 -0.9375 1.8125q0 0.921875 0.671875 1.515625q0.65625 0.609375 3.421875 1.234375q2.78125 0.625 3.8125 1.09375q1.5 0.6875 2.203125 1.75q0.71875 1.0625 0.71875 2.4375q0 1.375 -0.78125 2.59375q-0.78125 1.203125 -2.25 1.890625q-1.46875 0.671875 -3.3125 0.671875q-2.328125 0 -3.90625 -0.671875q-1.578125 -0.6875 -2.484375 -2.046875q-0.890625 -1.375 -0.9375 -3.09375zm15.9453125 -9.390625l0 -2.453125l2.265625 0l0 1.9375q0 1.5625 -0.359375 2.265625q-0.5 0.9375 -1.578125 1.421875l-0.515625 -0.828125q0.640625 -0.265625 0.953125 -0.8125q0.3125 -0.5625 0.34375 -1.53125l-1.109375 0zm3.640625 0l0 -2.453125l2.265625 0l0 1.9375q0 1.5625 -0.375 2.265625q-0.5 0.9375 -1.5625 1.421875l-0.515625 -0.828125q0.625 -0.265625 0.9375 -0.8125q0.3125 -0.5625 0.34375 -1.53125l-1.09375 0zm12.097656 14.90625l0 -10.8125l-1.875 0l0 -1.640625l1.875 0l0 -1.3125q0 -1.265625 0.21875 -1.875q0.296875 -0.8125 1.0625 -1.3125q0.78125 -0.515625 2.15625 -0.515625q0.890625 0 1.96875 0.203125l-0.3125 1.84375q-0.65625 -0.125 -1.25 -0.125q-0.953125 0 -1.359375 0.421875q-0.390625 0.40625 -0.390625 1.53125l0 1.140625l2.421875 0l0 1.640625l-2.421875 0l0 10.8125l-2.09375 0zm5.3710938 -6.21875q0 -3.46875 1.921875 -5.125q1.609375 -1.390625 3.921875 -1.390625q2.5625 0 4.1875 1.6875q1.625 1.6875 1.625 4.640625q0 2.40625 -0.71875 3.78125q-0.71875 1.375 -2.09375 2.140625q-1.375 0.765625 -3.0 0.765625q-2.625 0 -4.234375 -1.671875q-1.609375 -1.6875 -1.609375 -4.828125zm2.171875 0q0 2.390625 1.03125 3.578125q1.046875 1.1875 2.640625 1.1875q1.5625 0 2.609375 -1.1875q1.046875 -1.203125 1.046875 -3.65625q0 -2.3125 -1.0625 -3.5q-1.046875 -1.1875 -2.59375 -1.1875q-1.59375 0 -2.640625 1.1875q-1.03125 1.1875 -1.03125 3.578125zm11.941406 6.21875l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm13.832031 -3.71875l2.09375 -0.328125q0.171875 1.25 0.96875 1.921875q0.8125 0.671875 2.25 0.671875q1.453125 0 2.15625 -0.59375q0.703125 -0.59375 0.703125 -1.390625q0 -0.71875 -0.625 -1.125q-0.421875 -0.28125 -2.15625 -0.71875q-2.3125 -0.578125 -3.21875 -1.0q-0.890625 -0.4375 -1.359375 -1.1875q-0.453125 -0.765625 -0.453125 -1.671875q0 -0.828125 0.375 -1.53125q0.390625 -0.71875 1.046875 -1.1875q0.484375 -0.359375 1.328125 -0.609375q0.859375 -0.265625 1.828125 -0.265625q1.46875 0 2.578125 0.421875q1.109375 0.421875 1.625 1.15625q0.53125 0.71875 0.734375 1.921875l-2.0625 0.28125q-0.140625 -0.96875 -0.8125 -1.5q-0.671875 -0.546875 -1.90625 -0.546875q-1.453125 0 -2.078125 0.484375q-0.625 0.484375 -0.625 1.125q0 0.40625 0.265625 0.734375q0.25 0.34375 0.8125 0.5625q0.3125 0.125 1.859375 0.546875q2.234375 0.59375 3.109375 0.984375q0.890625 0.375 1.390625 1.109375q0.515625 0.71875 0.515625 1.796875q0 1.046875 -0.625 1.984375q-0.609375 0.9375 -1.765625 1.453125q-1.15625 0.5 -2.625 0.5q-2.421875 0 -3.703125 -1.0q-1.265625 -1.015625 -1.625 -3.0zm17.453125 1.828125l0.3125 1.859375q-0.890625 0.203125 -1.59375 0.203125q-1.15625 0 -1.796875 -0.359375q-0.625 -0.375 -0.890625 -0.96875q-0.25 -0.59375 -0.25 -2.484375l0 -7.171875l-1.546875 0l0 -1.640625l1.546875 0l0 -3.078125l2.09375 -1.265625l0 4.34375l2.125 0l0 1.640625l-2.125 0l0 7.28125q0 0.90625 0.109375 1.171875q0.125 0.25 0.375 0.40625q0.25 0.140625 0.71875 0.140625q0.34375 0 0.921875 -0.078125zm1.2773438 -4.328125q0 -3.46875 1.921875 -5.125q1.609375 -1.390625 3.921875 -1.390625q2.5625 0 4.1875 1.6875q1.625 1.6875 1.625 4.640625q0 2.40625 -0.71875 3.78125q-0.71875 1.375 -2.09375 2.140625q-1.375 0.765625 -3.0 0.765625q-2.625 0 -4.234375 -1.671875q-1.609375 -1.6875 -1.609375 -4.828125zm2.171875 0q0 2.390625 1.03125 3.578125q1.046875 1.1875 2.640625 1.1875q1.5625 0 2.609375 -1.1875q1.046875 -1.203125 1.046875 -3.65625q0 -2.3125 -1.0625 -3.5q-1.046875 -1.1875 -2.59375 -1.1875q-1.59375 0 -2.640625 1.1875q-1.03125 1.1875 -1.03125 3.578125zm11.941406 6.21875l0 -12.453125l1.890625 0l0 1.890625q0.734375 -1.328125 1.34375 -1.75q0.625 -0.421875 1.359375 -0.421875q1.0625 0 2.171875 0.6875l-0.734375 1.953125q-0.765625 -0.453125 -1.546875 -0.453125q-0.6875 0 -1.25 0.421875q-0.546875 0.40625 -0.78125 1.140625q-0.34375 1.125 -0.34375 2.46875l0 6.515625l-2.109375 0zm8.0234375 -14.75l0 -2.4375l2.109375 0l0 2.4375l-2.109375 0zm0 14.75l0 -12.453125l2.109375 0l0 12.453125l-2.109375 0zm5.3164062 0l0 -12.453125l1.90625 0l0 1.78125q1.375 -2.0625 3.953125 -2.0625q1.125 0 2.0625 0.40625q0.953125 0.40625 1.421875 1.0625q0.46875 0.65625 0.65625 1.5625q0.125 0.578125 0.125 2.046875l0 7.65625l-2.109375 0l0 -7.578125q0 -1.28125 -0.25 -1.921875q-0.25 -0.640625 -0.875 -1.015625q-0.625 -0.390625 -1.46875 -0.390625q-1.34375 0 -2.328125 0.859375q-0.984375 0.859375 -0.984375 3.25l0 6.796875l-2.109375 0zm12.972656 1.03125l2.046875 0.3125q0.125 0.9375 0.71875 1.375q0.78125 0.59375 2.140625 0.59375q1.46875 0 2.265625 -0.59375q0.796875 -0.578125 1.078125 -1.640625q0.15625 -0.640625 0.140625 -2.703125q-1.375 1.625 -3.4375 1.625q-2.5625 0 -3.96875 -1.84375q-1.40625 -1.859375 -1.40625 -4.453125q0 -1.78125 0.640625 -3.28125q0.640625 -1.515625 1.859375 -2.328125q1.234375 -0.828125 2.890625 -0.828125q2.203125 0 3.625 1.78125l0 -1.5l1.953125 0l0 10.765625q0 2.90625 -0.59375 4.109375q-0.59375 1.21875 -1.875 1.921875q-1.28125 0.703125 -3.15625 0.703125q-2.234375 0 -3.609375 -1.0q-1.359375 -1.0 -1.3125 -3.015625zm1.734375 -7.484375q0 2.453125 0.96875 3.578125q0.984375 1.125 2.453125 1.125q1.453125 0 2.4375 -1.109375q0.984375 -1.125 0.984375 -3.515625q0 -2.28125 -1.015625 -3.4375q-1.015625 -1.171875 -2.453125 -1.171875q-1.40625 0 -2.390625 1.140625q-0.984375 1.140625 -0.984375 3.390625zm20.609375 6.453125l-1.953125 0l0 -17.1875l2.109375 0l0 6.140625q1.328125 -1.6875 3.40625 -1.6875q1.140625 0 2.171875 0.46875q1.03125 0.46875 1.6875 1.3125q0.65625 0.828125 1.03125 2.015625q0.375 1.171875 0.375 2.53125q0 3.1875 -1.578125 4.9375q-1.578125 1.75 -3.796875 1.75q-2.203125 0 -3.453125 -1.84375l0 1.5625zm-0.03125 -6.3125q0 2.234375 0.609375 3.234375q1.0 1.625 2.703125 1.625q1.375 0 2.375 -1.203125q1.015625 -1.203125 1.015625 -3.578125q0 -2.4375 -0.96875 -3.59375q-0.953125 -1.171875 -2.328125 -1.171875q-1.390625 0 -2.40625 1.203125q-1.0 1.203125 -1.0 3.484375zm11.378906 6.3125l0 -17.1875l2.109375 0l0 17.1875l-2.109375 0zm4.5976562 -6.21875q0 -3.46875 1.921875 -5.125q1.609375 -1.390625 3.921875 -1.390625q2.5625 0 4.1875 1.6875q1.625 1.6875 1.625 4.640625q0 2.40625 -0.71875 3.78125q-0.71875 1.375 -2.09375 2.140625q-1.375 0.765625 -3.0 0.765625q-2.625 0 -4.234375 -1.671875q-1.609375 -1.6875 -1.609375 -4.828125zm2.171875 0q0 2.390625 1.03125 3.578125q1.046875 1.1875 2.640625 1.1875q1.5625 0 2.609375 -1.1875q1.046875 -1.203125 1.046875 -3.65625q0 -2.3125 -1.0625 -3.5q-1.046875 -1.1875 -2.59375 -1.1875q-1.59375 0 -2.640625 1.1875q-1.03125 1.1875 -1.03125 3.578125zm20.082031 1.65625l2.078125 0.265625q-0.34375 2.15625 -1.75 3.375q-1.390625 1.203125 -3.4375 1.203125q-2.546875 0 -4.109375 -1.671875q-1.546875 -1.671875 -1.546875 -4.78125q0 -2.015625 0.671875 -3.53125q0.671875 -1.515625 2.03125 -2.265625q1.359375 -0.765625 2.96875 -0.765625q2.03125 0 3.3125 1.03125q1.296875 1.03125 1.65625 2.90625l-2.046875 0.328125q-0.296875 -1.265625 -1.046875 -1.890625q-0.734375 -0.640625 -1.796875 -0.640625q-1.59375 0 -2.59375 1.15625q-0.984375 1.140625 -0.984375 3.609375q0 2.5 0.953125 3.640625q0.96875 1.140625 2.515625 1.140625q1.234375 0 2.0625 -0.765625q0.84375 -0.765625 1.0625 -2.34375zm3.890625 4.5625l0 -17.1875l2.109375 0l0 9.796875l5.0 -5.0625l2.71875 0l-4.75 4.625l5.234375 7.828125l-2.59375 0l-4.125 -6.359375l-1.484375 1.421875l0 4.9375l-2.109375 0zm20.308594 -14.296875l0 2.453125l-2.265625 0l0 -1.9375q0 -1.578125 0.375 -2.28125q0.5 -0.9375 1.5625 -1.40625l0.515625 0.8125q-0.640625 0.265625 -0.953125 0.8125q-0.296875 0.53125 -0.328125 1.546875l1.09375 0zm3.640625 0l0 2.453125l-2.265625 0l0 -1.9375q0 -1.578125 0.375 -2.28125q0.484375 -0.9375 1.5625 -1.40625l0.515625 0.8125q-0.65625 0.265625 -0.96875 0.8125q-0.296875 0.53125 -0.328125 1.546875l1.109375 0zm2.8828125 14.296875l0 -17.1875l6.4375 0q1.96875 0 3.15625 0.53125q1.1875 0.515625 1.859375 1.609375q0.6875 1.078125 0.6875 2.265625q0 1.09375 -0.609375 2.078125q-0.59375 0.96875 -1.796875 1.5625q1.5625 0.453125 2.390625 1.5625q0.84375 1.09375 0.84375 2.59375q0 1.203125 -0.515625 2.25q-0.5 1.03125 -1.25 1.59375q-0.75 0.5625 -1.890625 0.859375q-1.125 0.28125 -2.765625 0.28125l-6.546875 0zm2.265625 -9.96875l3.71875 0q1.515625 0 2.171875 -0.1875q0.859375 -0.265625 1.296875 -0.859375q0.4375 -0.59375 0.4375 -1.5q0 -0.859375 -0.40625 -1.5q-0.40625 -0.65625 -1.171875 -0.890625q-0.765625 -0.25 -2.609375 -0.25l-3.4375 0l0 5.1875zm0 7.9375l4.28125 0q1.09375 0 1.546875 -0.078125q0.78125 -0.140625 1.3125 -0.46875q0.53125 -0.328125 0.859375 -0.953125q0.34375 -0.625 0.34375 -1.453125q0 -0.953125 -0.5 -1.65625q-0.484375 -0.71875 -1.359375 -1.0q-0.875 -0.296875 -2.515625 -0.296875l-3.96875 0l0 5.90625zm12.9921875 -12.875l0 -2.453125l2.265625 0l0 1.9375q0 1.5625 -0.359375 2.265625q-0.5 0.9375 -1.578125 1.421875l-0.515625 -0.828125q0.640625 -0.265625 0.953125 -0.8125q0.3125 -0.5625 0.34375 -1.53125l-1.109375 0zm3.640625 0l0 -2.453125l2.265625 0l0 1.9375q0 1.5625 -0.375 2.265625q-0.5 0.9375 -1.5625 1.421875l-0.515625 -0.828125q0.625 -0.265625 0.9375 -0.8125q0.3125 -0.5625 0.34375 -1.53125l-1.09375 0zm8.8671875 10.671875q-0.015625 -0.421875 -0.015625 -0.625q0 -1.25 0.359375 -2.15625q0.25 -0.671875 0.828125 -1.359375q0.421875 -0.515625 1.515625 -1.46875q1.09375 -0.96875 1.421875 -1.546875q0.328125 -0.578125 0.328125 -1.25q0 -1.234375 -0.96875 -2.15625q-0.953125 -0.9375 -2.34375 -0.9375q-1.34375 0 -2.25 0.84375q-0.90625 0.84375 -1.1875 2.625l-2.15625 -0.25q0.28125 -2.40625 1.734375 -3.671875q1.453125 -1.28125 3.828125 -1.28125q2.515625 0 4.015625 1.375q1.5 1.359375 1.5 3.3125q0 1.125 -0.53125 2.078125q-0.515625 0.9375 -2.0625 2.296875q-1.03125 0.921875 -1.34375 1.359375q-0.3125 0.421875 -0.46875 0.984375q-0.15625 0.5625 -0.171875 1.828125l-2.03125 0zm-0.125 4.234375l0 -2.40625l2.40625 0l0 2.40625l-2.40625 0z" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.666668 199.10498l0 245.38583" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m340.52756 199.10498l0 245.38583" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m636.3884 199.10498l0 245.38583" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m932.2493 199.10498l0 245.38583" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 199.60367l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 240.80052l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 280.80054l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 320.80054l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 360.80054l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 402.39633l888.5801 0" fill-rule="nonzero"></path><path stroke="#9e9e9e" stroke-width="1.0" stroke-linecap="butt" d="m44.16798 443.99213l888.5801 0" fill-rule="nonzero"></path><path fill="#000000" d="m55.432293 226.52367l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm4.886429 0l0 -13.59375l4.687496 0q1.578125 0 2.421875 0.1875q1.15625 0.265625 1.984375 0.96875q1.078125 0.921875 1.609375 2.34375q0.53125 1.40625 0.53125 3.21875q0 1.546875 -0.359375 2.75q-0.359375 1.1875 -0.921875 1.984375q-0.5625 0.78125 -1.234375 1.234375q-0.671875 0.4375 -1.625 0.671875q-0.953125 0.234375 -2.1875 0.234375l-4.906246 0zm1.796875 -1.609375l2.9062462 0q1.34375 0 2.109375 -0.25q0.765625 -0.25 1.21875 -0.703125q0.640625 -0.640625 1.0 -1.71875q0.359375 -1.078125 0.359375 -2.625q0 -2.125 -0.703125 -3.265625q-0.703125 -1.15625 -1.703125 -1.546875q-0.71875 -0.28125 -2.328125 -0.28125l-2.8593712 0l0 10.390625zm14.644817 5.609375q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm2.634552 -8.375l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm13.927948 8.375l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m350.9338 226.52367l0 -13.59375l2.71875 0l3.21875 9.625q0.4375 1.34375 0.640625 2.015625q0.234375 -0.75 0.734375 -2.1875l3.25 -9.453125l2.421875 0l0 13.59375l-1.734375 0l0 -11.390625l-3.953125 11.390625l-1.625 0l-3.9375 -11.578125l0 11.578125l-1.734375 0zm15.603302 0l0 -13.59375l4.6875 0q1.578125 0 2.421875 0.1875q1.15625 0.265625 1.984375 0.96875q1.078125 0.921875 1.609375 2.34375q0.53125 1.40625 0.53125 3.21875q0 1.546875 -0.359375 2.75q-0.359375 1.1875 -0.921875 1.984375q-0.5625 0.78125 -1.234375 1.234375q-0.671875 0.4375 -1.625 0.671875q-0.953125 0.234375 -2.1875 0.234375l-4.90625 0zm1.796875 -1.609375l2.90625 0q1.34375 0 2.109375 -0.25q0.765625 -0.25 1.21875 -0.703125q0.640625 -0.640625 1.0 -1.71875q0.359375 -1.078125 0.359375 -2.625q0 -2.125 -0.703125 -3.265625q-0.703125 -1.15625 -1.703125 -1.546875q-0.71875 -0.28125 -2.328125 -0.28125l-2.859375 0l0 10.390625zm10.988586 -1.953125l1.765625 -0.15625q0.1875 1.28125 0.890625 1.9375q0.71875 0.640625 1.71875 0.640625q1.203125 0 2.03125 -0.90625q0.84375 -0.90625 0.84375 -2.421875q0 -1.421875 -0.8125 -2.25q-0.796875 -0.828125 -2.09375 -0.828125q-0.796875 0 -1.453125 0.375q-0.640625 0.359375 -1.015625 0.953125l-1.578125 -0.203125l1.328125 -7.0l6.765625 0l0 1.609375l-5.4375 0l-0.734375 3.640625q1.234375 -0.84375 2.578125 -0.84375q1.78125 0 3.0 1.234375q1.234375 1.234375 1.234375 3.171875q0 1.84375 -1.078125 3.1875q-1.3125 1.65625 -3.578125 1.65625q-1.859375 0 -3.03125 -1.03125q-1.171875 -1.046875 -1.34375 -2.765625zm14.031952 7.5625q-1.375 -1.75 -2.328125 -4.078125q-0.953125 -2.34375 -0.953125 -4.84375q0 -2.21875 0.703125 -4.234375q0.84375 -2.34375 2.578125 -4.671875l1.203125 0q-1.125 1.921875 -1.484375 2.75q-0.5625 1.28125 -0.890625 2.671875q-0.40625 1.734375 -0.40625 3.484375q0 4.46875 2.78125 8.921875l-1.203125 0zm3.165802 -4.0l0 -13.59375l5.109375 0q1.546875 0 2.484375 0.40625q0.953125 0.40625 1.484375 1.265625q0.53125 0.859375 0.53125 1.796875q0 0.875 -0.46875 1.65625q-0.46875 0.765625 -1.4375 1.234375q1.234375 0.359375 1.890625 1.234375q0.671875 0.875 0.671875 2.0625q0 0.953125 -0.40625 1.78125q-0.390625 0.8125 -0.984375 1.265625q-0.59375 0.4375 -1.5 0.671875q-0.890625 0.21875 -2.1875 0.21875l-5.1875 0zm1.796875 -7.890625l2.9375 0q1.203125 0 1.71875 -0.15625q0.6875 -0.203125 1.03125 -0.671875q0.359375 -0.46875 0.359375 -1.1875q0 -0.671875 -0.328125 -1.1875q-0.328125 -0.515625 -0.9375 -0.703125q-0.59375 -0.203125 -2.0625 -0.203125l-2.71875 0l0 4.109375zm0 6.28125l3.390625 0q0.875 0 1.21875 -0.0625q0.625 -0.109375 1.046875 -0.359375q0.421875 -0.265625 0.6875 -0.765625q0.265625 -0.5 0.265625 -1.140625q0 -0.765625 -0.390625 -1.328125q-0.390625 -0.5625 -1.078125 -0.78125q-0.6875 -0.234375 -1.984375 -0.234375l-3.15625 0l0 4.671875zm11.599823 5.609375l-1.1875 0q2.765625 -4.453125 2.765625 -8.921875q0 -1.734375 -0.390625 -3.453125q-0.328125 -1.390625 -0.890625 -2.671875q-0.359375 -0.84375 -1.484375 -2.78125l1.1875 0q1.75 2.328125 2.578125 4.671875q0.71875 2.015625 0.71875 4.234375q0 2.5 -0.96875 4.84375q-0.953125 2.328125 -2.328125 4.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m648.46655 226.52367l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm18.394836 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.125732 -5.8125l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.8323364 0.8125l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm9.297546 5.109375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm14.031982 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m61.447918 263.88052l-1.75 0l-3.421875 -3.9375l0 3.9375l-1.28125 0l0 -10.34375l1.28125 0l0 6.359375l3.296875 -3.375l1.6875 0l-3.453125 3.390625l3.640625 3.96875zm7.667446 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171871 0q0 1.125 0.6249962 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6874962 -0.25 -1.1249962 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0624962 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.14062119 0.40625 -0.18749619 0.890625l3.8749962 0zm9.3862 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.4487 0.4375q0 0.984375 -0.28125 1.71875q-0.265625 0.734375 -0.75 1.21875q-0.484375 0.484375 -1.140625 0.734375q-0.65625 0.234375 -1.421875 0.234375q-0.359375 0 -0.703125 -0.046875q-0.34375 -0.03125 -0.703125 -0.125l0 3.078125l-1.28125 0l0 -10.359375l1.140625 0l0.078125 1.234375q0.546875 -0.75 1.171875 -1.046875q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.34375 0.15625 0.734375 0.25q0.390625 0.078125 0.765625 0.078125q1.03125 0 1.609375 -0.703125q0.59375 -0.703125 0.59375 -2.109375zm9.5112 -1.03125q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625z" fill-rule="nonzero"></path><path fill="#000000" d="m355.41818 263.88052l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.1987 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620575 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm2.6987 0.234375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245575 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151825 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm2.85495 -1.203125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401825 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026825 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058075 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.370575 -9.15625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.4487 4.953125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.1987 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.808075 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 -3.796875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm2.79245 0.734375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339325 -0.453125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.6987 -4.90625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.6250305 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.31253052 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.839294 -0.8125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm14.94873 7.09375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058044 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm9.026855 8.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9331055 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375z" fill-rule="nonzero"></path><path fill="#000000" d="m652.6853 263.88052l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151855 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.558044 -0.71875q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.214355 -2.375q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm10.964294 8.390625q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.870605 -8.890625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.386169 -1.03125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.058105 3.0625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.683044 3.875q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.97998 2.71875l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.526794 5.9375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.44873 -0.09375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.386169 -6.078125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.058105 3.0625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.276794 5.75q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm8.183105 -2.421875q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.573669 5.625q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.276855 0.546875q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.386169 -3.015625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.401855 3.328125q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.401794 0.265625l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.120605 5.984375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.761169 -6.84375q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.19873 4.296875q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm6.8080444 3.0625l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.44873 0.28125q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.308044 -1.0q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm8.88623 3.984375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.745605 3.5625q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.979919 2.71875l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.433105 8.34375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875z" fill-rule="nonzero"></path><path fill="#000000" d="m61.447918 303.88052l-1.75 0l-3.421875 -3.9375l0 3.9375l-1.28125 0l0 -10.34375l1.28125 0l0 6.359375l3.296875 -3.375l1.6875 0l-3.453125 3.390625l3.640625 3.96875zm7.667446 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171871 0q0 1.125 0.6249962 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6874962 -0.25 -1.1249962 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0624962 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.14062119 0.40625 -0.18749619 0.890625l3.8749962 0zm9.3862 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.4487 0.4375q0 0.984375 -0.28125 1.71875q-0.265625 0.734375 -0.75 1.21875q-0.484375 0.484375 -1.140625 0.734375q-0.65625 0.234375 -1.421875 0.234375q-0.359375 0 -0.703125 -0.046875q-0.34375 -0.03125 -0.703125 -0.125l0 3.078125l-1.28125 0l0 -10.359375l1.140625 0l0.078125 1.234375q0.546875 -0.75 1.171875 -1.046875q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.34375 0.15625 0.734375 0.25q0.390625 0.078125 0.765625 0.078125q1.03125 0 1.609375 -0.703125q0.59375 -0.703125 0.59375 -2.109375zm9.1987 3.75l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875z" fill-rule="nonzero"></path><path fill="#000000" d="m355.41818 303.88052l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.1987 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620575 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm2.6987 0.234375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245575 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151825 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm2.85495 -1.203125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401825 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026825 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058075 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.370575 -9.15625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.4487 4.953125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.1987 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.808075 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 -3.796875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm2.79245 0.734375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339325 -0.453125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.6987 -4.90625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.6250305 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.31253052 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.839294 -0.8125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm14.94873 7.09375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058044 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm9.026855 8.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9331055 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375z" fill-rule="nonzero"></path><path fill="#000000" d="m652.77905 303.88052l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm1.4643555 -3.515625q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.44873 -1.75q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.323669 -4.140625l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm6.6206055 8.390625l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.698669 0.9375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.91748 0.203125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.526794 4.28125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.85498 2.140625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.636169 5.3125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm2.6831055 -0.5625q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.44873 -1.75q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.136169 1.1875q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.245605 -5.328125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.433044 -0.765625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm2.6830444 -0.5625q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm11.839355 3.609375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm8.198669 3.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.19873 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026855 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm7.0580444 0.265625l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.63623 -5.046875l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.058044 3.0625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.464355 4.59375q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm8.886169 3.984375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.495605 -8.125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.339294 3.609375q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.82373 -4.328125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0z" fill-rule="nonzero"></path><path fill="#000000" d="m61.447918 343.88052l-1.75 0l-3.421875 -3.9375l0 3.9375l-1.28125 0l0 -10.34375l1.28125 0l0 6.359375l3.296875 -3.375l1.6875 0l-3.453125 3.390625l3.640625 3.96875zm7.667446 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171871 0q0 1.125 0.6249962 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6874962 -0.25 -1.1249962 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0624962 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.14062119 0.40625 -0.18749619 0.890625l3.8749962 0zm9.3862 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.4487 0.4375q0 0.984375 -0.28125 1.71875q-0.265625 0.734375 -0.75 1.21875q-0.484375 0.484375 -1.140625 0.734375q-0.65625 0.234375 -1.421875 0.234375q-0.359375 0 -0.703125 -0.046875q-0.34375 -0.03125 -0.703125 -0.125l0 3.078125l-1.28125 0l0 -10.359375l1.140625 0l0.078125 1.234375q0.546875 -0.75 1.171875 -1.046875q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.34375 0.15625 0.734375 0.25q0.390625 0.078125 0.765625 0.078125q1.03125 0 1.609375 -0.703125q0.59375 -0.703125 0.59375 -2.109375zm9.29245 3.75l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875z" fill-rule="nonzero"></path><path fill="#000000" d="m355.41818 343.88052l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.1987 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620575 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm2.6987 0.234375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245575 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151825 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm2.85495 -1.203125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401825 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026825 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058075 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.370575 -9.15625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.4487 4.953125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.1987 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.808075 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 -3.796875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm2.79245 0.734375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339325 -0.453125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.6987 -4.90625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.6250305 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.31253052 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.839294 -0.8125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm14.94873 7.09375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058044 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm9.026855 8.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9331055 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375z" fill-rule="nonzero"></path><path fill="#ffff00" d="m645.3884 332.9957l257.8584 0l0 17.16098l-257.8584 0l0 -17.16098z" fill-rule="nonzero"></path><path fill="#000000" d="m652.77905 341.47427q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.26123 -0.59375q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm8.245544 0.5q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.38623 -3.015625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.401794 0.265625l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.026855 8.390625l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm7.9017944 -3.0625q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.8081055 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620544 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm7.7924805 3.75l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.604919 3.34375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm1.5581055 -3.515625q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm6.7455444 0.09375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.808105 1.5l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.464294 -0.046875l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.120605 5.984375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm8.948669 2.046875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm1.9643555 -3.25q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.276794 -4.78125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm7.8706055 5.328125q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.308044 3.0625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm7.5581055 -0.265625q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.464355 -0.046875l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.120544 5.984375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.19873 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.245544 -5.328125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm8.120605 5.984375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.198669 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.308105 3.0625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm7.8705444 -2.90625q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm8.35498 -0.125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375z" fill-rule="nonzero"></path><path fill="#000000" d="m61.447918 383.88052l-1.75 0l-3.421875 -3.9375l0 3.9375l-1.28125 0l0 -10.34375l1.28125 0l0 6.359375l3.296875 -3.375l1.6875 0l-3.453125 3.390625l3.640625 3.96875zm7.667446 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171871 0q0 1.125 0.6249962 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6874962 -0.25 -1.1249962 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0624962 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.14062119 0.40625 -0.18749619 0.890625l3.8749962 0zm9.3862 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.4487 0.4375q0 0.984375 -0.28125 1.71875q-0.265625 0.734375 -0.75 1.21875q-0.484375 0.484375 -1.140625 0.734375q-0.65625 0.234375 -1.421875 0.234375q-0.359375 0 -0.703125 -0.046875q-0.34375 -0.03125 -0.703125 -0.125l0 3.078125l-1.28125 0l0 -10.359375l1.140625 0l0.078125 1.234375q0.546875 -0.75 1.171875 -1.046875q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.34375 0.15625 0.734375 0.25q0.390625 0.078125 0.765625 0.078125q1.03125 0 1.609375 -0.703125q0.59375 -0.703125 0.59375 -2.109375zm9.10495 0.84375q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125z" fill-rule="nonzero"></path><path fill="#000000" d="m355.41818 383.88052l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.1987 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620575 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm2.6987 0.234375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245575 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151825 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm2.85495 -1.203125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401825 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026825 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058075 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.370575 -9.15625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.4487 4.953125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.1987 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.808075 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 -3.796875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm2.79245 0.734375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339325 -0.453125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.6987 -4.90625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.6250305 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.31253052 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.839294 -0.8125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm14.94873 7.09375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058044 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm9.026855 8.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9331055 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375z" fill-rule="nonzero"></path><path fill="#000000" d="m652.6853 383.88052l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.620605 -2.109375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.276794 5.28125q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.41748 0.03125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.589294 -6.203125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm8.85498 3.84375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245544 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.370605 -4.78125q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.261169 1.765625q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.245605 -2.265625q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.526794 4.84375q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm7.7924805 3.75l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.917419 -1.4375q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.01123 4.5625q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558044 -2.140625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.44873 2.3125l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm7.8080444 -3.0625q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.214355 3.0625l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151794 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm7.8862305 4.25l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.339355 5.4375q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm1.6517944 -0.609375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.808105 1.5l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9330444 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401855 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.604919 -5.40625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.51123 3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.401794 0.71875q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.276855 -1.109375q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.386169 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.38623 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0z" fill-rule="nonzero"></path><path fill="#000000" d="m61.447918 425.47632l-1.75 0l-3.421875 -3.9375l0 3.9375l-1.28125 0l0 -10.34375l1.28125 0l0 6.359375l3.296875 -3.375l1.6875 0l-3.453125 3.390625l3.640625 3.96875zm7.667446 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171871 0q0 1.125 0.6249962 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6874962 -0.25 -1.1249962 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0624962 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.14062119 0.40625 -0.18749619 0.890625l3.8749962 0zm9.3862 0.1875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.4487 0.4375q0 0.984375 -0.28125 1.71875q-0.265625 0.734375 -0.75 1.21875q-0.484375 0.484375 -1.140625 0.734375q-0.65625 0.234375 -1.421875 0.234375q-0.359375 0 -0.703125 -0.046875q-0.34375 -0.03125 -0.703125 -0.125l0 3.078125l-1.28125 0l0 -10.359375l1.140625 0l0.078125 1.234375q0.546875 -0.75 1.171875 -1.046875q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.34375 0.15625 0.734375 0.25q0.390625 0.078125 0.765625 0.078125q1.03125 0 1.609375 -0.703125q0.59375 -0.703125 0.59375 -2.109375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375z" fill-rule="nonzero"></path><path fill="#000000" d="m355.41818 425.47632l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.1987 3.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.620575 -3.546875q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm2.6987 0.234375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.245575 3.609375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.151825 -2.40625q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm2.85495 -1.203125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.401825 -0.203125q0 0.921875 -0.25 1.640625q-0.25 0.71875 -0.71875 1.21875q-0.46875 0.5 -1.140625 0.78125q-0.65625 0.265625 -1.484375 0.265625q-0.65625 0 -1.34375 -0.125q-0.671875 -0.125 -1.34375 -0.40625l0 -9.90625l1.28125 0l0 2.84375l-0.0625 1.359375q0.546875 -0.734375 1.171875 -1.03125q0.625 -0.3125 1.34375 -0.3125q0.625 0 1.09375 0.265625q0.484375 0.265625 0.8125 0.75q0.328125 0.46875 0.484375 1.15625q0.15625 0.671875 0.15625 1.5zm-1.296875 0.0625q0 -0.578125 -0.09375 -1.0625q-0.078125 -0.484375 -0.265625 -0.828125q-0.171875 -0.34375 -0.46875 -0.53125q-0.28125 -0.203125 -0.671875 -0.203125q-0.25 0 -0.5 0.078125q-0.25 0.078125 -0.515625 0.265625q-0.265625 0.171875 -0.5625 0.46875q-0.296875 0.296875 -0.625 0.734375l0 3.5625q0.359375 0.15625 0.75 0.25q0.390625 0.078125 0.75 0.078125q0.4375 0 0.828125 -0.140625q0.40625 -0.140625 0.703125 -0.46875q0.3125 -0.328125 0.484375 -0.859375q0.1875 -0.546875 0.1875 -1.34375zm9.7612 1.640625l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.026825 8.078125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058075 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.370575 -9.15625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.4487 4.953125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.1987 -0.75q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm7.808075 2.796875q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558075 -3.796875q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm2.79245 0.734375q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339325 -0.453125q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.6987 -4.90625q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm15.558105 4.328125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.6250305 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.31253052 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.839294 -0.8125q-1.015625 -0.21875 -1.734375 -0.21875q-1.71875 0 -1.71875 1.796875l0 1.296875l3.21875 0l0 1.0625l-3.21875 0l0 5.21875l-1.296875 0l0 -5.21875l-2.359375 0l0 -1.0625l2.359375 0l0 -1.21875q0 -2.9375 3.0625 -2.9375q0.765625 0 1.6875 0.171875l0 1.109375zm-7.703125 1.796875l0 0zm14.94873 7.09375q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058044 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm9.026794 -1.84375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm9.026855 8.34375l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm10.167419 1.234375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9331055 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.339294 1.203125q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375z" fill-rule="nonzero"></path><path fill="#ffff00" d="m645.3884 414.5915l257.8584 0l0 17.16098l-257.8584 0l0 -17.16098z" fill-rule="nonzero"></path><path fill="#000000" d="m652.59155 422.57007q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm8.245605 2.90625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm7.8080444 -3.0625q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.776855 0.953125l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm3.9330444 4.828125q0 -0.9375 0.25 -1.671875q0.265625 -0.734375 0.734375 -1.234375q0.46875 -0.5 1.125 -0.75q0.671875 -0.265625 1.484375 -0.265625q0.359375 0 0.6875 0.046875q0.34375 0.03125 0.671875 0.125l0 -3.078125l1.28125 0l0 10.34375l-1.140625 0l-0.03125 -1.390625q-0.546875 0.78125 -1.171875 1.15625q-0.609375 0.359375 -1.34375 0.359375q-0.625 0 -1.109375 -0.25q-0.46875 -0.265625 -0.796875 -0.75q-0.3125 -0.484375 -0.484375 -1.15625q-0.15625 -0.671875 -0.15625 -1.484375zm1.3125 -0.09375q0 1.34375 0.390625 2.0q0.390625 0.65625 1.109375 0.65625q0.484375 0 1.015625 -0.4375q0.53125 -0.4375 1.125 -1.28125l0 -3.421875q-0.3125 -0.140625 -0.6875 -0.21875q-0.375 -0.078125 -0.75 -0.078125q-1.046875 0 -1.625 0.671875q-0.578125 0.671875 -0.578125 2.109375zm13.276855 -4.78125l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm7.6205444 8.125q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.370605 -2.640625q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125zm7.7455444 2.640625q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.058105 0q-0.5 0.1875 -1.03125 0.28125q-0.515625 0.09375 -1.078125 0.09375q-1.734375 0 -2.6875 -0.9375q-0.9375 -0.953125 -0.9375 -2.78125q0 -0.859375 0.265625 -1.5625q0.28125 -0.71875 0.765625 -1.21875q0.5 -0.515625 1.171875 -0.78125q0.6875 -0.28125 1.5 -0.28125q0.578125 0 1.078125 0.078125q0.5 0.078125 0.953125 0.265625l0 1.21875q-0.484375 -0.25 -0.984375 -0.359375q-0.484375 -0.125 -1.015625 -0.125q-0.484375 0 -0.921875 0.1875q-0.4375 0.1875 -0.765625 0.546875q-0.328125 0.34375 -0.53125 0.859375q-0.1875 0.5 -0.1875 1.140625q0 1.328125 0.640625 2.0q0.65625 0.65625 1.8125 0.65625q0.515625 0 1.0 -0.109375q0.5 -0.125 0.953125 -0.359375l0 1.1875zm8.558044 0.265625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.058105 -4.0625q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.604919 -0.53125q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.620605 1.796875q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.526855 -1.71875q0 1.09375 -0.234375 2.0q-0.21875 0.90625 -0.671875 1.5625q-0.4375 0.640625 -1.109375 1.0q-0.65625 0.34375 -1.546875 0.34375q-0.765625 0 -1.40625 -0.28125q-0.625 -0.296875 -1.078125 -0.890625q-0.4375 -0.59375 -0.6875 -1.53125q-0.234375 -0.9375 -0.234375 -2.203125q0 -1.09375 0.21875 -2.0q0.234375 -0.921875 0.671875 -1.5625q0.453125 -0.65625 1.109375 -1.0q0.671875 -0.359375 1.5625 -0.359375q0.765625 0 1.390625 0.296875q0.625 0.28125 1.078125 0.890625q0.453125 0.59375 0.6875 1.53125q0.25 0.921875 0.25 2.203125zm-1.296875 0.046875q0 -0.25 -0.015625 -0.5q-0.015625 -0.25 -0.046875 -0.484375l-4.046875 3.015625q0.109375 0.375 0.28125 0.703125q0.171875 0.328125 0.40625 0.5625q0.234375 0.21875 0.53125 0.359375q0.3125 0.125 0.703125 0.125q0.5 0 0.90625 -0.234375q0.40625 -0.25 0.6875 -0.71875q0.28125 -0.484375 0.4375 -1.1875q0.15625 -0.71875 0.15625 -1.640625zm-4.375 -0.09375q0 0.234375 0 0.46875q0 0.21875 0.03125 0.421875l4.046875 -2.984375q-0.109375 -0.375 -0.28125 -0.6875q-0.171875 -0.3125 -0.40625 -0.53125q-0.234375 -0.21875 -0.53125 -0.34375q-0.296875 -0.125 -0.671875 -0.125q-0.5 0 -0.90625 0.25q-0.40625 0.234375 -0.703125 0.71875q-0.28125 0.46875 -0.4375 1.1875q-0.140625 0.703125 -0.140625 1.625zm13.511169 4.828125l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm8.526855 -2.109375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.636169 5.3125q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.183105 2.953125l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.620544 -2.109375l-1.640625 0l0 2.109375l-1.296875 0l0 -2.109375l-4.609375 0l0 -1.125l4.078125 -6.34375l1.828125 0l0 6.34375l1.640625 0l0 1.125zm-2.9375 -6.234375l-3.328125 5.109375l3.328125 0l0 -5.109375zm10.433105 8.34375l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.089294 -5.328125q0 1.40625 -0.34375 2.421875q-0.328125 1.0 -0.984375 1.65625q-0.65625 0.640625 -1.640625 0.953125q-0.96875 0.296875 -2.25 0.296875l-0.796875 0l0 -1.109375l0.890625 0q0.953125 0 1.640625 -0.1875q0.6875 -0.203125 1.140625 -0.5625q0.453125 -0.375 0.6875 -0.90625q0.25 -0.53125 0.3125 -1.21875l0.03125 -0.296875q-0.46875 0.28125 -1.078125 0.453125q-0.59375 0.15625 -1.296875 0.15625q-0.71875 0 -1.265625 -0.21875q-0.546875 -0.21875 -0.921875 -0.59375q-0.359375 -0.375 -0.546875 -0.890625q-0.171875 -0.53125 -0.171875 -1.15625q0 -0.65625 0.234375 -1.234375q0.25 -0.578125 0.6875 -1.0q0.4375 -0.4375 1.03125 -0.6875q0.609375 -0.25 1.34375 -0.25q0.71875 0 1.3125 0.234375q0.609375 0.234375 1.046875 0.765625q0.4375 0.515625 0.6875 1.359375q0.25 0.828125 0.25 2.015625zm-3.34375 -3.328125q-0.421875 0 -0.765625 0.140625q-0.34375 0.125 -0.609375 0.390625q-0.25 0.265625 -0.390625 0.640625q-0.140625 0.375 -0.140625 0.875q0 0.4375 0.09375 0.796875q0.109375 0.34375 0.328125 0.59375q0.234375 0.25 0.578125 0.390625q0.359375 0.125 0.84375 0.125q0.265625 0 0.546875 -0.046875q0.296875 -0.0625 0.5625 -0.140625q0.28125 -0.09375 0.53125 -0.203125q0.25 -0.125 0.453125 -0.265625q0 -0.9375 -0.140625 -1.5625q-0.140625 -0.640625 -0.40625 -1.015625q-0.265625 -0.390625 -0.640625 -0.546875q-0.375 -0.171875 -0.84375 -0.171875zm11.464355 8.65625l-6.3125 0l0 -1.140625l2.46875 -2.46875q0.609375 -0.59375 0.984375 -1.03125q0.390625 -0.4375 0.59375 -0.796875q0.21875 -0.375 0.296875 -0.6875q0.078125 -0.328125 0.078125 -0.703125q0 -0.34375 -0.109375 -0.65625q-0.09375 -0.328125 -0.296875 -0.5625q-0.1875 -0.25 -0.5 -0.390625q-0.3125 -0.140625 -0.75 -0.140625q-0.609375 0 -1.109375 0.28125q-0.5 0.265625 -0.921875 0.6875l-0.703125 -0.828125q0.546875 -0.578125 1.25 -0.921875q0.703125 -0.34375 1.640625 -0.34375q0.640625 0 1.15625 0.1875q0.53125 0.1875 0.90625 0.546875q0.390625 0.359375 0.59375 0.890625q0.21875 0.515625 0.21875 1.15625q0 0.5625 -0.15625 1.03125q-0.140625 0.46875 -0.4375 0.9375q-0.296875 0.453125 -0.75 0.953125q-0.453125 0.5 -1.0625 1.09375l-1.734375 1.6875l4.65625 0l0 1.21875zm7.9642944 0l-6.0 0l0 -1.1875l2.453125 0l0 -6.984375l-2.296875 1.25l-0.46875 -1.09375l3.046875 -1.59375l1.125 0l0 8.421875l2.140625 0l0 1.1875zm8.089355 -8.390625l-4.015625 8.390625l-1.453125 0l4.171875 -8.390625l-5.171875 0l0 -1.1875l6.46875 0l0 1.1875zm6.6205444 8.390625l-0.03125 -0.984375q-0.59375 0.59375 -1.21875 0.859375q-0.609375 0.25 -1.296875 0.25q-0.625 0 -1.078125 -0.15625q-0.4375 -0.15625 -0.734375 -0.4375q-0.28125 -0.28125 -0.421875 -0.65625q-0.140625 -0.390625 -0.140625 -0.84375q0 -1.09375 0.828125 -1.71875q0.828125 -0.640625 2.4375 -0.640625l1.515625 0l0 -0.640625q0 -0.65625 -0.421875 -1.046875q-0.40625 -0.390625 -1.265625 -0.390625q-0.625 0 -1.234375 0.140625q-0.59375 0.140625 -1.234375 0.40625l0 -1.15625q0.234375 -0.09375 0.53125 -0.171875q0.296875 -0.078125 0.625 -0.140625q0.328125 -0.078125 0.6875 -0.109375q0.359375 -0.046875 0.734375 -0.046875q0.65625 0 1.1875 0.15625q0.546875 0.140625 0.90625 0.4375q0.375 0.296875 0.5625 0.75q0.203125 0.453125 0.203125 1.078125l0 5.0625l-1.140625 0zm-0.140625 -3.34375l-1.609375 0q-0.484375 0 -0.828125 0.09375q-0.34375 0.09375 -0.5625 0.265625q-0.21875 0.171875 -0.328125 0.421875q-0.09375 0.25 -0.09375 0.5625q0 0.203125 0.0625 0.40625q0.0625 0.1875 0.203125 0.34375q0.15625 0.140625 0.390625 0.234375q0.234375 0.078125 0.5625 0.078125q0.4375 0 1.0 -0.265625q0.578125 -0.265625 1.203125 -0.84375l0 -1.296875zm9.69873 0.9375q0 0.609375 -0.25 1.09375q-0.25 0.46875 -0.703125 0.796875q-0.453125 0.3125 -1.0625 0.484375q-0.59375 0.15625 -1.3125 0.15625q-0.78125 0 -1.375 -0.171875q-0.59375 -0.171875 -1.0 -0.484375q-0.40625 -0.3125 -0.609375 -0.75q-0.203125 -0.4375 -0.203125 -0.953125q0 -0.875 0.484375 -1.515625q0.5 -0.640625 1.515625 -1.15625q-0.9375 -0.484375 -1.375 -1.0625q-0.421875 -0.578125 -0.421875 -1.328125q0 -0.46875 0.1875 -0.890625q0.1875 -0.4375 0.578125 -0.765625q0.390625 -0.34375 0.96875 -0.546875q0.578125 -0.203125 1.359375 -0.203125q0.734375 0 1.296875 0.15625q0.5625 0.15625 0.9375 0.453125q0.390625 0.296875 0.578125 0.71875q0.1875 0.40625 0.1875 0.921875q0 0.828125 -0.46875 1.421875q-0.46875 0.578125 -1.3125 1.015625q0.421875 0.21875 0.78125 0.484375q0.375 0.25 0.640625 0.5625q0.265625 0.3125 0.421875 0.703125q0.15625 0.390625 0.15625 0.859375zm-1.53125 -4.953125q0 -0.640625 -0.453125 -0.953125q-0.453125 -0.328125 -1.28125 -0.328125q-0.828125 0 -1.28125 0.3125q-0.453125 0.3125 -0.453125 0.9375q0 0.296875 0.109375 0.546875q0.109375 0.234375 0.328125 0.453125q0.234375 0.203125 0.578125 0.40625q0.34375 0.203125 0.828125 0.421875q0.828125 -0.390625 1.21875 -0.8125q0.40625 -0.421875 0.40625 -0.984375zm0.140625 5.046875q0 -0.265625 -0.09375 -0.515625q-0.078125 -0.265625 -0.3125 -0.515625q-0.21875 -0.25 -0.609375 -0.5q-0.375 -0.25 -0.96875 -0.5q-0.5 0.234375 -0.84375 0.46875q-0.328125 0.234375 -0.546875 0.484375q-0.203125 0.25 -0.296875 0.515625q-0.078125 0.265625 -0.078125 0.546875q0 0.328125 0.140625 0.59375q0.140625 0.25 0.390625 0.421875q0.25 0.171875 0.59375 0.265625q0.34375 0.09375 0.75 0.09375q0.390625 0 0.734375 -0.078125q0.34375 -0.09375 0.59375 -0.25q0.25 -0.171875 0.390625 -0.421875q0.15625 -0.25 0.15625 -0.609375zm9.448669 -1.75q0 0.265625 -0.015625 0.453125q0 0.1875 -0.015625 0.34375l-5.171875 0q0 1.125 0.625 1.734375q0.640625 0.59375 1.828125 0.59375q0.3125 0 0.640625 -0.015625q0.328125 -0.03125 0.625 -0.0625q0.296875 -0.046875 0.5625 -0.09375q0.28125 -0.0625 0.515625 -0.140625l0 1.046875q-0.515625 0.15625 -1.171875 0.234375q-0.65625 0.09375 -1.359375 0.09375q-0.9375 0 -1.625 -0.25q-0.6875 -0.25 -1.125 -0.734375q-0.421875 -0.5 -0.640625 -1.203125q-0.203125 -0.703125 -0.203125 -1.59375q0 -0.78125 0.21875 -1.46875q0.21875 -0.703125 0.640625 -1.21875q0.4375 -0.53125 1.0625 -0.828125q0.625 -0.3125 1.421875 -0.3125q0.765625 0 1.359375 0.25q0.59375 0.234375 1.0 0.6875q0.40625 0.4375 0.609375 1.078125q0.21875 0.625 0.21875 1.40625zm-1.328125 -0.1875q0.015625 -0.484375 -0.109375 -0.890625q-0.109375 -0.40625 -0.359375 -0.703125q-0.234375 -0.296875 -0.609375 -0.453125q-0.359375 -0.171875 -0.84375 -0.171875q-0.421875 0 -0.765625 0.171875q-0.34375 0.15625 -0.59375 0.453125q-0.25 0.28125 -0.40625 0.703125q-0.140625 0.40625 -0.1875 0.890625l3.875 0zm9.495605 1.21875q0 0.65625 -0.234375 1.234375q-0.234375 0.578125 -0.6875 1.015625q-0.4375 0.421875 -1.0625 0.671875q-0.609375 0.234375 -1.359375 0.234375q-0.796875 0 -1.40625 -0.25q-0.609375 -0.25 -1.015625 -0.765625q-0.40625 -0.53125 -0.625 -1.328125q-0.203125 -0.796875 -0.203125 -1.890625q0 -0.734375 0.09375 -1.421875q0.09375 -0.6875 0.3125 -1.296875q0.21875 -0.609375 0.578125 -1.109375q0.375 -0.5 0.921875 -0.859375q0.546875 -0.375 1.28125 -0.578125q0.734375 -0.203125 1.71875 -0.203125l0.9375 0l0 1.125l-1.015625 0q-0.859375 0 -1.5 0.203125q-0.625 0.203125 -1.046875 0.578125q-0.421875 0.375 -0.65625 0.90625q-0.21875 0.515625 -0.28125 1.171875l-0.03125 0.296875q0.46875 -0.265625 1.0625 -0.421875q0.609375 -0.171875 1.3125 -0.171875q0.71875 0 1.265625 0.21875q0.546875 0.203125 0.90625 0.578125q0.375 0.375 0.546875 0.90625q0.1875 0.53125 0.1875 1.15625zm-1.328125 0.078125q0 -0.4375 -0.109375 -0.796875q-0.109375 -0.359375 -0.34375 -0.59375q-0.21875 -0.25 -0.5625 -0.375q-0.34375 -0.140625 -0.828125 -0.140625q-0.28125 0 -0.578125 0.046875q-0.28125 0.046875 -0.5625 0.140625q-0.265625 0.09375 -0.515625 0.21875q-0.25 0.109375 -0.453125 0.234375q0 0.953125 0.125 1.59375q0.140625 0.625 0.390625 1.015625q0.265625 0.375 0.640625 0.53125q0.390625 0.15625 0.890625 0.15625q0.421875 0 0.765625 -0.125q0.34375 -0.140625 0.59375 -0.40625q0.25 -0.265625 0.390625 -0.640625q0.15625 -0.375 0.15625 -0.859375zm9.026794 -0.109375q0 0.71875 -0.3125 1.3125q-0.296875 0.578125 -0.84375 1.0q-0.53125 0.40625 -1.265625 0.640625q-0.734375 0.234375 -1.578125 0.234375q-0.21875 0 -0.46875 -0.015625q-0.234375 0 -0.484375 -0.015625q-0.234375 -0.015625 -0.46875 -0.046875q-0.234375 -0.015625 -0.421875 -0.046875l0 -1.15625q0.40625 0.09375 0.90625 0.140625q0.515625 0.046875 1.03125 0.046875q0.59375 0 1.0625 -0.140625q0.46875 -0.140625 0.796875 -0.390625q0.328125 -0.265625 0.5 -0.640625q0.171875 -0.375 0.171875 -0.828125q0 -0.90625 -0.640625 -1.3125q-0.640625 -0.40625 -1.84375 -0.40625l-1.8125 0l0 -4.890625l5.15625 0l0 1.125l-3.953125 0l0 2.6875l0.84375 0q0.6875 0 1.328125 0.125q0.65625 0.125 1.15625 0.4375q0.515625 0.296875 0.828125 0.828125q0.3125 0.515625 0.3125 1.3125zm8.120605 0.15625q0 0.625 -0.265625 1.1875q-0.25 0.546875 -0.765625 0.96875q-0.515625 0.40625 -1.296875 0.640625q-0.765625 0.234375 -1.796875 0.234375q-0.578125 0 -1.03125 -0.03125q-0.453125 -0.03125 -0.84375 -0.09375l0 -1.140625q0.453125 0.078125 0.953125 0.125q0.515625 0.046875 1.03125 0.046875q0.71875 0 1.21875 -0.125q0.515625 -0.140625 0.84375 -0.375q0.328125 -0.25 0.46875 -0.59375q0.140625 -0.34375 0.140625 -0.765625q0 -0.40625 -0.171875 -0.6875q-0.171875 -0.296875 -0.5 -0.5q-0.3125 -0.203125 -0.765625 -0.296875q-0.4375 -0.09375 -0.953125 -0.09375l-1.09375 0l0 -1.046875l1.109375 0q0.421875 0 0.78125 -0.109375q0.359375 -0.125 0.609375 -0.328125q0.25 -0.21875 0.375 -0.53125q0.140625 -0.3125 0.140625 -0.703125q0 -0.765625 -0.46875 -1.109375q-0.46875 -0.359375 -1.375 -0.359375q-0.484375 0 -1.0 0.09375q-0.5 0.09375 -1.09375 0.28125l0 -1.109375q0.25 -0.09375 0.53125 -0.15625q0.28125 -0.078125 0.5625 -0.125q0.28125 -0.046875 0.5625 -0.0625q0.28125 -0.03125 0.53125 -0.03125q0.765625 0 1.34375 0.171875q0.578125 0.15625 0.96875 0.46875q0.390625 0.296875 0.578125 0.75q0.203125 0.4375 0.203125 0.984375q0 0.8125 -0.421875 1.375q-0.421875 0.5625 -1.15625 0.890625q0.375 0.046875 0.734375 0.234375q0.375 0.171875 0.65625 0.453125q0.296875 0.265625 0.46875 0.640625q0.1875 0.375 0.1875 0.828125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m284.04724 136.9462l391.90552 0l0 51.181107l-391.90552 0z" fill-rule="nonzero"></path><path fill="#000000" d="m319.1797 158.57675l-3.796875 -12.453125l2.171875 0l1.984375 7.1875l0.734375 2.671875q0.046875 -0.203125 0.640625 -2.5625l1.984375 -7.296875l2.171875 0l1.859375 7.21875l0.625 2.390625l0.71875 -2.40625l2.125 -7.203125l2.046875 0l-3.890625 12.453125l-2.1875 0l-1.984375 -7.453125l-0.46875 -2.125l-2.53125 9.578125l-2.203125 0zm23.566406 -4.015625l2.171875 0.28125q-0.515625 1.90625 -1.90625 2.96875q-1.390625 1.046875 -3.5625 1.046875q-2.734375 0 -4.34375 -1.671875q-1.59375 -1.6875 -1.59375 -4.734375q0 -3.140625 1.609375 -4.875q1.625 -1.734375 4.203125 -1.734375q2.5 0 4.078125 1.703125q1.59375 1.703125 1.59375 4.78125q0 0.1875 -0.015625 0.5625l-9.28125 0q0.109375 2.046875 1.15625 3.140625q1.046875 1.09375 2.609375 1.09375q1.15625 0 1.96875 -0.609375q0.828125 -0.609375 1.3125 -1.953125zm-6.9375 -3.40625l6.953125 0q-0.140625 -1.5625 -0.796875 -2.359375q-1.0 -1.21875 -2.609375 -1.21875q-1.453125 0 -2.453125 0.984375q-0.984375 0.96875 -1.09375 2.59375zm11.769531 -7.328125l0 -2.4375l2.109375 0l0 2.4375l-2.109375 0zm0 14.75l0 -12.453125l2.109375 0l0 12.453125l-2.109375 0zm4.9414062 1.03125l2.046875 0.3125q0.125 0.9375 0.71875 1.375q0.78125 0.59375 2.140625 0.59375q1.46875 0 2.265625 -0.59375q0.796875 -0.578125 1.078125 -1.640625q0.15625 -0.640625 0.140625 -2.703125q-1.375 1.625 -3.4375 1.625q-2.5625 0 -3.96875 -1.84375q-1.40625 -1.859375 -1.40625 -4.453125q0 -1.78125 0.640625 -3.28125q0.640625 -1.515625 1.859375 -2.328125q1.234375 -0.828125 2.890625 -0.828125q2.203125 0 3.625 1.78125l0 -1.5l1.953125 0l0 10.765625q0 2.90625 -0.59375 4.109375q-0.59375 1.21875 -1.875 1.921875q-1.28125 0.703125 -3.15625 0.703125q-2.234375 0 -3.609375 -1.0q-1.359375 -1.0 -1.3125 -3.015625zm1.734375 -7.484375q0 2.453125 0.96875 3.578125q0.984375 1.125 2.453125 1.125q1.453125 0 2.4375 -1.109375q0.984375 -1.125 0.984375 -3.515625q0 -2.28125 -1.015625 -3.4375q-1.015625 -1.171875 -2.453125 -1.171875q-1.40625 0 -2.390625 1.140625q-0.984375 1.140625 -0.984375 3.390625zm11.988281 6.453125l0 -17.1875l2.109375 0l0 6.171875q1.484375 -1.71875 3.734375 -1.71875q1.375 0 2.390625 0.546875q1.03125 0.546875 1.46875 1.515625q0.4375 0.953125 0.4375 2.78125l0 7.890625l-2.109375 0l0 -7.890625q0 -1.578125 -0.6875 -2.296875q-0.6875 -0.71875 -1.9375 -0.71875q-0.9375 0 -1.765625 0.484375q-0.828125 0.484375 -1.1875 1.3125q-0.34375 0.828125 -0.34375 2.296875l0 6.8125l-2.109375 0zm17.957031 -1.890625l0.3125 1.859375q-0.890625 0.203125 -1.59375 0.203125q-1.15625 0 -1.796875 -0.359375q-0.625 -0.375 -0.890625 -0.96875q-0.25 -0.59375 -0.25 -2.484375l0 -7.171875l-1.546875 0l0 -1.640625l1.546875 0l0 -3.078125l2.09375 -1.265625l0 4.34375l2.125 0l0 1.640625l-2.125 0l0 7.28125q0 0.90625 0.109375 1.171875q0.125 0.25 0.375 0.40625q0.25 0.140625 0.71875 0.140625q0.34375 0 0.921875 -0.078125zm19.835938 -8.21875l-11.34375 0l0 -1.96875l11.34375 0l0 1.96875zm0 5.21875l-11.34375 0l0 -1.96875l11.34375 0l0 1.96875zm9.777344 4.890625l0 -17.1875l3.421875 0l4.0625 12.171875q0.5625 1.703125 0.828125 2.546875q0.296875 -0.9375 0.90625 -2.765625l4.125 -11.953125l3.046875 0l0 17.1875l-2.1875 0l0 -14.375l-4.984375 14.375l-2.0625 0l-4.96875 -14.625l0 14.625l-2.1875 0zm20.070312 0l0 -17.1875l5.90625 0q2.015625 0 3.0625 0.25q1.484375 0.34375 2.515625 1.234375q1.359375 1.140625 2.03125 2.9375q0.6875 1.78125 0.6875 4.078125q0 1.953125 -0.46875 3.46875q-0.453125 1.515625 -1.171875 2.515625q-0.703125 0.984375 -1.5625 1.546875q-0.84375 0.5625 -2.046875 0.859375q-1.203125 0.296875 -2.765625 0.296875l-6.1875 0zm2.265625 -2.03125l3.671875 0q1.703125 0 2.65625 -0.3125q0.96875 -0.3125 1.546875 -0.890625q0.8125 -0.8125 1.265625 -2.171875q0.453125 -1.375 0.453125 -3.3125q0 -2.703125 -0.890625 -4.140625q-0.890625 -1.453125 -2.15625 -1.9375q-0.90625 -0.359375 -2.9375 -0.359375l-3.609375 0l0 13.125zm14.207031 -2.46875l2.21875 -0.1875q0.234375 1.609375 1.125 2.4375q0.90625 0.8125 2.171875 0.8125q1.53125 0 2.578125 -1.140625q1.0625 -1.15625 1.0625 -3.0625q0 -1.796875 -1.015625 -2.84375q-1.015625 -1.046875 -2.65625 -1.046875q-1.015625 0 -1.84375 0.46875q-0.8125 0.453125 -1.28125 1.203125l-1.984375 -0.265625l1.65625 -8.828125l8.546875 0l0 2.015625l-6.859375 0l-0.921875 4.625q1.546875 -1.078125 3.25 -1.078125q2.25 0 3.796875 1.5625q1.546875 1.546875 1.546875 4.0q0 2.328125 -1.359375 4.03125q-1.65625 2.09375 -4.515625 2.09375q-2.34375 0 -3.828125 -1.3125q-1.484375 -1.3125 -1.6875 -3.484375zm17.957031 9.546875q-1.734375 -2.203125 -2.953125 -5.15625q-1.203125 -2.953125 -1.203125 -6.109375q0 -2.796875 0.90625 -5.34375q1.046875 -2.96875 3.25 -5.90625l1.515625 0q-1.421875 2.4375 -1.875 3.46875q-0.71875 1.625 -1.125 3.375q-0.5 2.203125 -0.5 4.40625q0 5.640625 3.5 11.265625l-1.515625 0zm4.6171875 -5.046875l0 -17.1875l2.28125 0l0 17.1875l-2.28125 0zm6.2929688 0l0 -17.1875l5.90625 0q2.015625 0 3.0625 0.25q1.484375 0.34375 2.515625 1.234375q1.359375 1.140625 2.03125 2.9375q0.6875 1.78125 0.6875 4.078125q0 1.953125 -0.46875 3.46875q-0.453125 1.515625 -1.171875 2.515625q-0.703125 0.984375 -1.5625 1.546875q-0.84375 0.5625 -2.046875 0.859375q-1.203125 0.296875 -2.765625 0.296875l-6.1875 0zm2.265625 -2.03125l3.671875 0q1.703125 0 2.65625 -0.3125q0.96875 -0.3125 1.546875 -0.890625q0.8125 -0.8125 1.265625 -2.171875q0.453125 -1.375 0.453125 -3.3125q0 -2.703125 -0.890625 -4.140625q-0.890625 -1.453125 -2.15625 -1.9375q-0.90625 -0.359375 -2.9375 -0.359375l-3.609375 0l0 13.125zm18.816406 7.078125q-1.734375 -2.203125 -2.953125 -5.15625q-1.203125 -2.953125 -1.203125 -6.109375q0 -2.796875 0.90625 -5.34375q1.046875 -2.96875 3.25 -5.90625l1.515625 0q-1.421875 2.4375 -1.875 3.46875q-0.71875 1.625 -1.125 3.375q-0.5 2.203125 -0.5 4.40625q0 5.640625 3.5 11.265625l-1.515625 0zm3.4609375 -10.5625l2.140625 -0.1875q0.15625 1.28125 0.703125 2.109375q0.5625 0.828125 1.734375 1.34375q1.171875 0.5 2.640625 0.5q1.296875 0 2.296875 -0.375q1.0 -0.390625 1.484375 -1.0625q0.484375 -0.6875 0.484375 -1.484375q0 -0.796875 -0.46875 -1.40625q-0.46875 -0.609375 -1.546875 -1.015625q-0.6875 -0.265625 -3.0625 -0.828125q-2.359375 -0.578125 -3.3125 -1.078125q-1.234375 -0.640625 -1.84375 -1.59375q-0.59375 -0.96875 -0.59375 -2.140625q0 -1.3125 0.734375 -2.4375q0.75 -1.125 2.15625 -1.703125q1.421875 -0.59375 3.15625 -0.59375q1.90625 0 3.359375 0.609375q1.46875 0.609375 2.25 1.8125q0.796875 1.1875 0.84375 2.703125l-2.171875 0.171875q-0.171875 -1.640625 -1.1875 -2.46875q-1.015625 -0.828125 -3.0 -0.828125q-2.0625 0 -3.015625 0.765625q-0.9375 0.75 -0.9375 1.8125q0 0.921875 0.671875 1.515625q0.65625 0.609375 3.421875 1.234375q2.78125 0.625 3.8125 1.09375q1.5 0.6875 2.203125 1.75q0.71875 1.0625 0.71875 2.4375q0 1.375 -0.78125 2.59375q-0.78125 1.203125 -2.25 1.890625q-1.46875 0.671875 -3.3125 0.671875q-2.328125 0 -3.90625 -0.671875q-1.578125 -0.6875 -2.484375 -2.046875q-0.890625 -1.375 -0.9375 -3.09375zm17.898438 10.5625l-1.515625 0q3.5 -5.625 3.5 -11.265625q0 -2.203125 -0.5 -4.359375q-0.390625 -1.765625 -1.109375 -3.375q-0.453125 -1.0625 -1.890625 -3.515625l1.515625 0q2.203125 2.9375 3.25 5.90625q0.90625 2.546875 0.90625 5.34375q0 3.15625 -1.21875 6.109375q-1.203125 2.953125 -2.9375 5.15625zm17.707031 -7.828125l0 -4.703125l-4.671875 0l0 -1.96875l4.671875 0l0 -4.6875l1.984375 0l0 4.6875l4.6875 0l0 1.96875l-4.6875 0l0 4.703125l-1.984375 0zm16.449219 2.78125l0 -17.1875l3.421875 0l4.0625 12.171875q0.5625 1.703125 0.828125 2.546875q0.296875 -0.9375 0.90625 -2.765625l4.125 -11.953125l3.046875 0l0 17.1875l-2.1875 0l0 -14.375l-4.984375 14.375l-2.0625 0l-4.96875 -14.625l0 14.625l-2.1875 0zm20.070312 0l0 -17.1875l5.90625 0q2.015625 0 3.0625 0.25q1.484375 0.34375 2.515625 1.234375q1.359375 1.140625 2.03125 2.9375q0.6875 1.78125 0.6875 4.078125q0 1.953125 -0.46875 3.46875q-0.453125 1.515625 -1.171875 2.515625q-0.703125 0.984375 -1.5625 1.546875q-0.84375 0.5625 -2.046875 0.859375q-1.203125 0.296875 -2.765625 0.296875l-6.1875 0zm2.265625 -2.03125l3.671875 0q1.703125 0 2.65625 -0.3125q0.96875 -0.3125 1.546875 -0.890625q0.8125 -0.8125 1.265625 -2.171875q0.453125 -1.375 0.453125 -3.3125q0 -2.703125 -0.890625 -4.140625q-0.890625 -1.453125 -2.15625 -1.9375q-0.90625 -0.359375 -2.9375 -0.359375l-3.609375 0l0 13.125zm14.207031 -2.46875l2.21875 -0.1875q0.234375 1.609375 1.125 2.4375q0.90625 0.8125 2.171875 0.8125q1.53125 0 2.578125 -1.140625q1.0625 -1.15625 1.0625 -3.0625q0 -1.796875 -1.015625 -2.84375q-1.015625 -1.046875 -2.65625 -1.046875q-1.015625 0 -1.84375 0.46875q-0.8125 0.453125 -1.28125 1.203125l-1.984375 -0.265625l1.65625 -8.828125l8.546875 0l0 2.015625l-6.859375 0l-0.921875 4.625q1.546875 -1.078125 3.25 -1.078125q2.25 0 3.796875 1.5625q1.546875 1.546875 1.546875 4.0q0 2.328125 -1.359375 4.03125q-1.65625 2.09375 -4.515625 2.09375q-2.34375 0 -3.828125 -1.3125q-1.484375 -1.3125 -1.6875 -3.484375zm17.957031 9.546875q-1.734375 -2.203125 -2.953125 -5.15625q-1.203125 -2.953125 -1.203125 -6.109375q0 -2.796875 0.90625 -5.34375q1.046875 -2.96875 3.25 -5.90625l1.515625 0q-1.421875 2.4375 -1.875 3.46875q-0.71875 1.625 -1.125 3.375q-0.5 2.203125 -0.5 4.40625q0 5.640625 3.5 11.265625l-1.515625 0zm4.1484375 -5.046875l0 -17.1875l6.4375 0q1.96875 0 3.15625 0.53125q1.1875 0.515625 1.859375 1.609375q0.6875 1.078125 0.6875 2.265625q0 1.09375 -0.609375 2.078125q-0.59375 0.96875 -1.796875 1.5625q1.5625 0.453125 2.390625 1.5625q0.84375 1.09375 0.84375 2.59375q0 1.203125 -0.515625 2.25q-0.5 1.03125 -1.25 1.59375q-0.75 0.5625 -1.890625 0.859375q-1.125 0.28125 -2.765625 0.28125l-6.546875 0zm2.265625 -9.96875l3.71875 0q1.515625 0 2.171875 -0.1875q0.859375 -0.265625 1.296875 -0.859375q0.4375 -0.59375 0.4375 -1.5q0 -0.859375 -0.40625 -1.5q-0.40625 -0.65625 -1.171875 -0.890625q-0.765625 -0.25 -2.609375 -0.25l-3.4375 0l0 5.1875zm0 7.9375l4.28125 0q1.09375 0 1.546875 -0.078125q0.78125 -0.140625 1.3125 -0.46875q0.53125 -0.328125 0.859375 -0.953125q0.34375 -0.625 0.34375 -1.453125q0 -0.953125 -0.5 -1.65625q-0.484375 -0.71875 -1.359375 -1.0q-0.875 -0.296875 -2.515625 -0.296875l-3.96875 0l0 5.90625zm14.9453125 7.078125l-1.515625 0q3.5 -5.625 3.5 -11.265625q0 -2.203125 -0.5 -4.359375q-0.390625 -1.765625 -1.109375 -3.375q-0.453125 -1.0625 -1.890625 -3.515625l1.515625 0q2.203125 2.9375 3.25 5.90625q0.90625 2.546875 0.90625 5.34375q0 3.15625 -1.21875 6.109375q-1.203125 2.953125 -2.9375 5.15625zm7.9921875 0l-1.515625 0q3.5 -5.625 3.5 -11.265625q0 -2.203125 -0.5 -4.359375q-0.390625 -1.765625 -1.109375 -3.375q-0.453125 -1.0625 -1.890625 -3.515625l1.515625 0q2.203125 2.9375 3.25 5.90625q0.90625 2.546875 0.90625 5.34375q0 3.15625 -1.21875 6.109375q-1.203125 2.953125 -2.9375 5.15625z" fill-rule="nonzero"></path></g></svg>
+
--- /dev/null
+<?xml version="1.0" standalone="yes"?>
+
+<svg version="1.1" viewBox="0.0 0.0 1338.0 1283.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="p.0"><path d="m0 0l1338.0 0l0 1283.0l-1338.0 0l0 -1283.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l1338.0 0l0 1283.0l-1338.0 0z" fill-rule="nonzero"></path><path fill="#d9ead3" d="m529.084 59.792652l179.27557 0l0 94.645676l-179.27557 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m529.084 59.792652l179.27557 0l0 94.645676l-179.27557 0z" fill-rule="nonzero"></path><path fill="#000000" d="m573.0276 114.035484l-3.609375 -13.59375l1.84375 0l2.0625 8.90625q0.34375 1.40625 0.578125 2.78125q0.515625 -2.171875 0.609375 -2.515625l2.59375 -9.171875l2.171875 0l1.953125 6.875q0.734375 2.5625 1.046875 4.8125q0.265625 -1.28125 0.6875 -2.953125l2.125 -8.734375l1.8125 0l-3.734375 13.59375l-1.734375 0l-2.859375 -10.359375q-0.359375 -1.296875 -0.421875 -1.59375q-0.21875 0.9375 -0.40625 1.59375l-2.890625 10.359375l-1.828125 0zm14.389893 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.266357 4.921875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.2438965 0l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm10.859375 0l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm15.594482 1.828125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813171 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.890625 3.609375l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m186.2126 85.77165l342.2677 2.708664" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m186.2126 85.77165l336.26794 2.6611862" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m522.4674 90.08451l4.5510254 -1.6157684l-4.5248413 -1.6875916z" fill-rule="evenodd"></path><path fill="#d9ead3" d="m464.64304 281.8714l154.07877 -82.47244l154.07874 82.47244l-154.07874 82.47244z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m464.64304 281.8714l154.07877 -82.47244l154.07874 82.47244l-154.07874 82.47244z" fill-rule="nonzero"></path><path fill="#000000" d="m550.6512 266.79138l5.234375 -13.593735l1.9375 0l5.5625 13.593735l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.7031097 -0.96875 -2.8124847q-0.265625 1.3125 -0.734375 2.5937347l-1.5 4.0zm9.8029175 5.578125l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm9.750732 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm10.297546 3.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm9.40625 -3.796875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm14.9158325 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735107 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.2506714 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375z" fill-rule="nonzero"></path><path fill="#000000" d="m558.36993 287.57263q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.516296 1.328125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 0l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.328125 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm21.933289 -0.234375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813232 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm5.6257324 4.9375l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.813171 5.0l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm10.926086 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375z" fill-rule="nonzero"></path><path fill="#000000" d="m559.7137 309.182q-0.828125 0.921875 -1.8125 1.390625q-0.96875 0.453125 -2.09375 0.453125q-2.09375 0 -3.3125 -1.40625q-1.0 -1.15625 -1.0 -2.578125q0 -1.265625 0.8125 -2.28125q0.8125 -1.015625 2.421875 -1.78125q-0.90625 -1.0625 -1.21875 -1.71875q-0.296875 -0.65625 -0.296875 -1.265625q0 -1.234375 0.953125 -2.125q0.953125 -0.90625 2.421875 -0.90625q1.390625 0 2.265625 0.859375q0.890625 0.84375 0.890625 2.046875q0 1.9375 -2.5625 3.3125l2.4375 3.09375q0.421875 -0.8125 0.640625 -1.890625l1.734375 0.375q-0.4375 1.78125 -1.203125 2.9375q0.9375 1.234375 2.125 2.078125l-1.125 1.328125q-1.0 -0.640625 -2.078125 -1.921875zm-3.40625 -7.078125q1.09375 -0.640625 1.40625 -1.125q0.328125 -0.484375 0.328125 -1.0625q0 -0.703125 -0.453125 -1.140625q-0.4375 -0.4375 -1.09375 -0.4375q-0.671875 0 -1.125 0.4375q-0.453125 0.421875 -0.453125 1.0625q0 0.3125 0.15625 0.65625q0.171875 0.34375 0.5 0.734375l0.734375 0.875zm2.359375 5.765625l-3.0625 -3.796875q-1.359375 0.8125 -1.84375 1.5q-0.46875 0.6875 -0.46875 1.375q0 0.8125 0.65625 1.703125q0.671875 0.890625 1.875 0.890625q0.75 0 1.546875 -0.46875q0.8125 -0.46875 1.296875 -1.203125zm17.329956 1.703125q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.516357 1.328125l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.328125 0l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.328125 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.015625 -8.75l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm5.6760864 0l-1.546875 0l0 -13.59375l1.65625 0l0 4.84375q1.0625 -1.328125 2.703125 -1.328125q0.90625 0 1.71875 0.375q0.8125 0.359375 1.328125 1.03125q0.53125 0.65625 0.828125 1.59375q0.296875 0.9375 0.296875 2.0q0 2.53125 -1.25 3.921875q-1.25 1.375 -3.0 1.375q-1.75 0 -2.734375 -1.453125l0 1.234375zm-0.015625 -5.0q0 1.765625 0.46875 2.5625q0.796875 1.28125 2.140625 1.28125q1.09375 0 1.890625 -0.9375q0.796875 -0.953125 0.796875 -2.84375q0 -1.921875 -0.765625 -2.84375q-0.765625 -0.921875 -1.84375 -0.921875q-1.09375 0 -1.890625 0.953125q-0.796875 0.953125 -0.796875 2.75zm8.813171 5.0l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm10.926086 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm12.235107 2.53125q0 -0.34375 0 -0.5q0 -0.984375 0.265625 -1.703125q0.21875 -0.546875 0.671875 -1.09375q0.328125 -0.390625 1.1875 -1.15625q0.875 -0.765625 1.125 -1.21875q0.265625 -0.453125 0.265625 -1.0q0 -0.96875 -0.765625 -1.703125q-0.75 -0.734375 -1.859375 -0.734375q-1.0625 0 -1.78125 0.671875q-0.703125 0.65625 -0.9375 2.078125l-1.71875 -0.203125q0.234375 -1.90625 1.375 -2.90625q1.15625 -1.015625 3.03125 -1.015625q2.0 0 3.1875 1.09375q1.1875 1.078125 1.1875 2.609375q0 0.890625 -0.421875 1.640625q-0.40625 0.75 -1.625 1.828125q-0.8125 0.734375 -1.0625 1.078125q-0.25 0.34375 -0.375 0.796875q-0.125 0.4375 -0.140625 1.4375l-1.609375 0zm-0.09375 3.34375l0 -1.90625l1.890625 0l0 1.90625l-1.890625 0z" fill-rule="nonzero"></path><path fill="#d9ead3" d="m848.9265 239.90552l156.34644 0l0 88.59842l-156.34644 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m848.9265 239.90552l156.34644 0l0 88.59842l-156.34644 0z" fill-rule="nonzero"></path><path fill="#000000" d="m865.75464 274.7966l0 -1.609375l5.765625 0l0 5.046875q-1.328125 1.0625 -2.75 1.59375q-1.40625 0.53125 -2.890625 0.53125q-2.0 0 -3.640625 -0.859375q-1.625 -0.859375 -2.46875 -2.484375q-0.828125 -1.625 -0.828125 -3.625q0 -1.984375 0.828125 -3.703125q0.828125 -1.71875 2.390625 -2.546875q1.5625 -0.84375 3.59375 -0.84375q1.46875 0 2.65625 0.484375q1.203125 0.46875 1.875 1.328125q0.671875 0.84375 1.03125 2.21875l-1.625 0.4375q-0.3125 -1.03125 -0.765625 -1.625q-0.453125 -0.59375 -1.296875 -0.953125q-0.84375 -0.359375 -1.875 -0.359375q-1.234375 0 -2.140625 0.375q-0.890625 0.375 -1.453125 1.0q-0.546875 0.609375 -0.84375 1.34375q-0.53125 1.25 -0.53125 2.734375q0 1.8125 0.625 3.046875q0.640625 1.21875 1.828125 1.8125q1.203125 0.59375 2.546875 0.59375q1.171875 0 2.28125 -0.453125q1.109375 -0.453125 1.6875 -0.953125l0 -2.53125l-4.0 0zm14.683289 2.15625l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm12.766357 4.375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm6.694702 1.5l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9783325 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.375 -1.984375q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735046 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.9069824 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.6658325 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" d="m859.58276 302.12473l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm4.7614136 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.6033325 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281921 4.921875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm19.442871 0l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm10.0217285 5.578125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm10.9435425 7.140625l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm9.460388 -4.375l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm19.584167 1.203125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm8.9626465 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.34375 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#d9ead3" d="m467.042 484.1076l154.07874 -74.80313l154.07874 74.80313l-154.07874 74.80316z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m467.042 484.1076l154.07874 -74.80313l154.07874 74.80313l-154.07874 74.80316z" fill-rule="nonzero"></path><path fill="#000000" d="m553.94073 486.65262l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm19.584229 1.203125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438171 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.328125 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.015625 -8.75l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.5042114 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm22.309021 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.000732 5.875l3.59375 -5.125l-3.328125 -4.734375l2.09375 0l1.515625 2.3125q0.421875 0.65625 0.671875 1.109375q0.421875 -0.609375 0.765625 -1.09375l1.65625 -2.328125l1.984375 0l-3.390625 4.640625l3.65625 5.21875l-2.046875 0l-2.03125 -3.0625l-0.53125 -0.828125l-2.59375 3.890625l-2.015625 0zm10.453125 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.4572754 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm13.65625 1.4375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.8552246 -1.4375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm13.125 -0.40625q0 -0.34375 0 -0.5q0 -0.984375 0.265625 -1.703125q0.21875 -0.546875 0.671875 -1.09375q0.328125 -0.390625 1.1875 -1.15625q0.875 -0.765625 1.125 -1.21875q0.265625 -0.453125 0.265625 -1.0q0 -0.96875 -0.765625 -1.703125q-0.75 -0.734375 -1.859375 -0.734375q-1.0625 0 -1.78125 0.671875q-0.703125 0.65625 -0.9375 2.078125l-1.71875 -0.203125q0.234375 -1.90625 1.375 -2.90625q1.15625 -1.015625 3.03125 -1.015625q2.0 0 3.1875 1.09375q1.1875 1.078125 1.1875 2.609375q0 0.890625 -0.421875 1.640625q-0.40625 0.75 -1.625 1.828125q-0.8125 0.734375 -1.0625 1.078125q-0.25 0.34375 -0.375 0.796875q-0.125 0.4375 -0.140625 1.4375l-1.609375 0zm-0.09375 3.34375l0 -1.90625l1.890625 0l0 1.90625l-1.890625 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m618.7218 154.43832l1.1968384 48.0" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m618.7218 154.43832l1.0472412 42.00186" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m618.11786 196.48135l1.7643433 4.495514l1.5380859 -4.5778503z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m896.65094 455.34122l2.3936768 43.653534" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m896.65094 455.34122l2.0651855 37.662506" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m897.06683 493.09418l1.8977661 4.440857l1.4007568 -4.621704z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m772.80054 281.8714l76.12598 1.669281" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m772.80054 281.8714l70.12744 1.5377502" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m842.8917 285.0605l4.573242 -1.5518494l-4.5007935 -1.750824z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m620.52234 360.3176l1.1968384 48.0" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m620.52234 360.3176l1.0472412 42.00183" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m619.9184 402.36063l1.7643433 4.495514l1.5380859 -4.5778503z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m585.021 367.1076l58.80316 0l0 34.4252l-58.80316 0z" fill-rule="nonzero"></path><path fill="#000000" d="m595.4741 394.02762l0 -13.59375l1.84375 0l7.140625 10.671875l0 -10.671875l1.71875 0l0 13.59375l-1.84375 0l-7.140625 -10.6875l0 10.6875l-1.71875 0zm12.644836 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m788.84515 248.8924l58.80316 0l0 34.4252l-58.80316 0z" fill-rule="nonzero"></path><path fill="#000000" d="m803.142 275.81238l0 -5.765625l-5.234375 -7.828125l2.1875 0l2.671875 4.09375q0.75 1.15625 1.390625 2.296875q0.609375 -1.0625 1.484375 -2.40625l2.625 -3.984375l2.109375 0l-5.4375 7.828125l0 5.765625l-1.796875 0zm15.1466675 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375z" fill-rule="nonzero"></path><path fill="#d9ead3" d="m845.084 442.14172l156.34644 0l0 88.59845l-156.34644 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m845.084 442.14172l156.34644 0l0 88.59845l-156.34644 0z" fill-rule="nonzero"></path><path fill="#000000" d="m861.9121 477.0328l0 -1.609375l5.765625 0l0 5.046875q-1.328125 1.0625 -2.75 1.59375q-1.40625 0.53125 -2.890625 0.53125q-2.0 0 -3.640625 -0.859375q-1.625 -0.859375 -2.46875 -2.484375q-0.828125 -1.625 -0.828125 -3.625q0 -1.984375 0.828125 -3.703125q0.828125 -1.71875 2.390625 -2.546875q1.5625 -0.84375 3.59375 -0.84375q1.46875 0 2.65625 0.484375q1.203125 0.46875 1.875 1.328125q0.671875 0.84375 1.03125 2.21875l-1.625 0.4375q-0.3125 -1.03125 -0.765625 -1.625q-0.453125 -0.59375 -1.296875 -0.953125q-0.84375 -0.359375 -1.875 -0.359375q-1.234375 0 -2.140625 0.375q-0.890625 0.375 -1.453125 1.0q-0.546875 0.609375 -0.84375 1.34375q-0.53125 1.25 -0.53125 2.734375q0 1.8125 0.625 3.046875q0.640625 1.21875 1.828125 1.8125q1.203125 0.59375 2.546875 0.59375q1.171875 0 2.28125 -0.453125q1.109375 -0.453125 1.6875 -0.953125l0 -2.53125l-4.0 0zm14.683289 2.15625l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm12.766357 4.375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm6.694763 1.5l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.375 -1.984375q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735107 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.9069214 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.6658325 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" d="m855.74023 504.36093l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm4.7614136 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.6033325 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm19.44281 0l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm10.0217285 5.578125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm10.9435425 7.140625l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm9.460388 -4.375l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm19.584167 1.203125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm8.9627075 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.34375 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094421 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m768.958 484.1076l76.12598 1.6693115" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m768.958 484.1076l70.12744 1.5377808" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m839.0492 487.2967l4.573242 -1.5518494l-4.5007935 -1.750824z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m785.0026 451.1286l58.80316 0l0 34.4252l-58.80316 0z" fill-rule="nonzero"></path><path fill="#000000" d="m799.2995 478.0486l0 -5.765625l-5.234375 -7.828125l2.1875 0l2.671875 4.09375q0.75 1.15625 1.390625 2.296875q0.609375 -1.0625 1.484375 -2.40625l2.625 -3.984375l2.109375 0l-5.4375 7.828125l0 5.765625l-1.796875 0zm15.1467285 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438171 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m1093.5826 486.44095l3.4645996 -377.88977" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1093.5826 486.44095l3.4645996 -377.88977" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m1005.27295 284.2047l89.60632 1.6378174" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1005.27295 284.2047l83.6073 1.5281677" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m1088.8501 287.38434l4.567505 -1.5685425l-4.507202 -1.734375z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m1099.9213 111.42519l-391.55908 -2.8661423" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1099.9213 111.42519l-385.5592 -2.8222198" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m714.37415 106.95129l-4.550049 1.6184692l4.525879 1.684906z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m1001.4304 485.62204l89.60632 1.6378174" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m1001.4304 485.62204l83.6073 1.5281372" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m1085.0076 488.80167l4.567505 -1.5685425l-4.50708 -1.734375z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m621.1207 558.91077l0.12597656 76.81891" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m621.1207 558.91077l0.1161499 70.81891" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m619.58514 629.73236l1.6591797 4.5354004l1.6442871 -4.5408325z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m579.0289 573.6352l47.338562 0l0 34.42517l-47.338562 0z" fill-rule="nonzero"></path><path fill="#000000" d="m589.482 600.5552l0 -13.59375l1.84375 0l7.140625 10.671875l0 -10.671875l1.71875 0l0 13.59375l-1.84375 0l-7.140625 -10.6875l0 10.6875l-1.71875 0zm12.644836 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125z" fill-rule="nonzero"></path><path fill="#ead1dc" d="m545.084 634.39105l156.34644 0l0 70.26776l-156.34644 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m545.084 634.39105l156.34644 0l0 70.26776l-156.34644 0z" fill-rule="nonzero"></path><path fill="#000000" d="m557.92773 654.44495l-3.609375 -13.59375l1.84375 0l2.0625 8.90625q0.34375 1.40625 0.578125 2.78125q0.515625 -2.171875 0.609375 -2.515625l2.59375 -9.171875l2.171875 0l1.953125 6.875q0.734375 2.5625 1.046875 4.8125q0.265625 -1.28125 0.6875 -2.953125l2.125 -8.734375l1.8125 0l-3.734375 13.59375l-1.734375 0l-2.859375 -10.359375q-0.359375 -1.296875 -0.421875 -1.59375q-0.21875 0.9375 -0.40625 1.59375l-2.890625 10.359375l-1.828125 0zm21.764893 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.078857 5.875l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm10.613586 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.265625 -1.3125q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm22.290771 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm14.293396 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.297607 3.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819824 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047546 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" d="m557.1621 676.44495l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.660461 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7854614 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270386 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm19.215271 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm7.9645386 0.28125q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.9313965 0.8125l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047607 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm12.766357 4.375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125z" fill-rule="nonzero"></path><path fill="#000000" d="m554.05273 698.44495l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm10.0217285 5.578125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm10.9435425 7.140625l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm8.601013 0.234375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm11.585327 -0.234375l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm3.5510864 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm8.985107 5.734375l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm9.313171 -6.578125l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.1292114 0l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m603.2966 782.2992l2.3937378 43.653564" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m603.2966 782.2992l2.0652466 37.662598" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m603.7125 820.0522l1.8977051 4.440857l1.4008179 -4.621704z" fill-rule="evenodd"></path><path fill="#bf9000" d="m512.5171 813.52496l114.74011 -60.960632l114.74017 60.960632l-114.74017 60.96057z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m512.5171 813.52496l114.74011 -60.960632l114.74017 60.960632l-114.74017 60.96057z" fill-rule="nonzero"></path><path fill="#000000" d="m605.663 816.06995l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm12.4436035 0l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm12.5060425 -2.25q0 -3.390625 1.8125 -5.296875q1.828125 -1.921875 4.703125 -1.921875q1.875 0 3.390625 0.90625q1.515625 0.890625 2.296875 2.5q0.796875 1.609375 0.796875 3.65625q0 2.0625 -0.84375 3.703125q-0.828125 1.625 -2.359375 2.46875q-1.53125 0.84375 -3.296875 0.84375q-1.921875 0 -3.4375 -0.921875q-1.5 -0.9375 -2.28125 -2.53125q-0.78125 -1.609375 -0.78125 -3.40625zm1.859375 0.03125q0 2.453125 1.3125 3.875q1.328125 1.40625 3.3125 1.40625q2.03125 0 3.34375 -1.421875q1.3125 -1.4375 1.3125 -4.0625q0 -1.65625 -0.5625 -2.890625q-0.546875 -1.234375 -1.640625 -1.921875q-1.078125 -0.6875 -2.421875 -0.6875q-1.90625 0 -3.28125 1.3125q-1.375 1.3125 -1.375 4.390625z" fill-rule="nonzero"></path><path fill="#f1c232" d="m677.6772 941.51184l179.27557 0l0 94.64563l-179.27557 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m677.6772 941.51184l179.27557 0l0 94.64563l-179.27557 0z" fill-rule="nonzero"></path><path fill="#000000" d="m725.6051 990.4265l0 -1.609375l5.765625 0l0 5.046875q-1.328125 1.0625 -2.75 1.59375q-1.40625 0.53125 -2.890625 0.53125q-2.0 0 -3.640625 -0.859375q-1.625 -0.859375 -2.46875 -2.484375q-0.828125 -1.625 -0.828125 -3.625q0 -1.984375 0.828125 -3.703125q0.828125 -1.71875 2.390625 -2.546875q1.5625 -0.84375 3.59375 -0.84375q1.46875 0 2.65625 0.484375q1.203125 0.46875 1.875 1.328125q0.671875 0.84375 1.03125 2.21875l-1.625 0.4375q-0.3125 -1.03125 -0.765625 -1.625q-0.453125 -0.59375 -1.296875 -0.953125q-0.84375 -0.359375 -1.875 -0.359375q-1.234375 0 -2.140625 0.375q-0.890625 0.375 -1.453125 1.0q-0.546875 0.609375 -0.84375 1.34375q-0.53125 1.25 -0.53125 2.734375q0 1.8125 0.625 3.046875q0.640625 1.21875 1.828125 1.8125q1.203125 0.59375 2.546875 0.59375q1.171875 0 2.28125 -0.453125q1.109375 -0.453125 1.6875 -0.953125l0 -2.53125l-4.0 0zm7.9332886 5.328125l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm21.978333 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0944824 -6.75l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.0979004 0l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm15.796875 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm10.531982 4.9375l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm7.5788574 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270386 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#ffd966" d="m400.60892 941.51184l179.2756 0l0 94.64563l-179.2756 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m400.60892 941.51184l179.2756 0l0 94.64563l-179.2756 0z" fill-rule="nonzero"></path><path fill="#000000" d="m422.49536 995.75464l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.250702 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.75 -0.234375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm6.228302 0l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm16.813202 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0788574 4.9375l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm22.290802 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm13.043396 6.109375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm11.616577 3.546875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.188232 1.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm11.828125 2.9375l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm18.035461 0l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m627.2572 874.48553l0 33.513184l-137.00787 0l0 33.510498" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m627.2572 874.48553l0 33.513123l-137.00787 0l0 30.083435" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m490.24933 938.0821l-1.1245728 -1.1245728l1.1245728 3.0897827l1.1246033 -3.0897827z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m627.2572 874.48553l0 33.513184l140.06299 0l0 33.510498" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m627.2572 874.48553l0 33.513123l140.06299 0l0 30.083435" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m767.3202 938.0821l-1.1245728 -1.1245728l1.1245728 3.0897827l1.1245728 -3.0897827z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m733.7454 1068.1392l137.00787 0l0 48.0l-137.00787 0z" fill-rule="nonzero"></path><path fill="#000000" d="m742.7142 1095.0591l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm16.256042 5.578125l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm7.5788574 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270386 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm19.215271 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020386 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.297607 4.921875l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m1027.8976 907.0079l229.48035 0l0 94.64569l-229.48035 0z" fill-rule="nonzero"></path><path fill="#000000" d="m1038.3976 933.92786l0 -13.59375l6.03125 0q1.8125 0 2.75 0.359375q0.953125 0.359375 1.515625 1.296875q0.5625 0.921875 0.5625 2.046875q0 1.453125 -0.9375 2.453125q-0.921875 0.984375 -2.890625 1.25q0.71875 0.34375 1.09375 0.671875q0.78125 0.734375 1.484375 1.8125l2.375 3.703125l-2.265625 0l-1.796875 -2.828125q-0.796875 -1.21875 -1.3125 -1.875q-0.5 -0.65625 -0.90625 -0.90625q-0.40625 -0.265625 -0.8125 -0.359375q-0.3125 -0.078125 -1.015625 -0.078125l-2.078125 0l0 6.046875l-1.796875 0zm1.796875 -7.59375l3.859375 0q1.234375 0 1.921875 -0.25q0.703125 -0.265625 1.0625 -0.828125q0.375 -0.5625 0.375 -1.21875q0 -0.96875 -0.703125 -1.578125q-0.703125 -0.625 -2.21875 -0.625l-4.296875 0l0 4.5zm18.176147 4.421875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm9.281982 -6.765625l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.1135254 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9782715 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547607 2.265625l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm6.546875 2.109375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm10.366577 0l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020996 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm13.18396 4.921875l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm10.0217285 5.578125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm10.9436035 7.140625l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0z" fill-rule="nonzero"></path><path fill="#000000" d="m1037.757 951.55286l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm19.584229 1.203125l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm8.9626465 0l-3.75 -9.859375l1.765625 0l2.125 5.90625q0.34375 0.953125 0.625 1.984375q0.21875 -0.78125 0.625 -1.875l2.1875 -6.015625l1.71875 0l-3.734375 9.859375l-1.5625 0zm13.34375 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094482 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm18.423096 0l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.6604 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7854004 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270996 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" d="m1037.757 973.55286l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm12.4436035 0l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm12.5061035 -2.25q0 -3.390625 1.8125 -5.296875q1.828125 -1.921875 4.703125 -1.921875q1.875 0 3.390625 0.90625q1.515625 0.890625 2.296875 2.5q0.796875 1.609375 0.796875 3.65625q0 2.0625 -0.84375 3.703125q-0.828125 1.625 -2.359375 2.46875q-1.53125 0.84375 -3.296875 0.84375q-1.921875 0 -3.4375 -0.921875q-1.5 -0.9375 -2.28125 -2.53125q-0.78125 -1.609375 -0.78125 -3.40625zm1.859375 0.03125q0 2.453125 1.3125 3.875q1.328125 1.40625 3.3125 1.40625q2.03125 0 3.34375 -1.421875q1.3125 -1.4375 1.3125 -4.0625q0 -1.65625 -0.5625 -2.890625q-0.546875 -1.234375 -1.640625 -1.921875q-1.078125 -0.6875 -2.421875 -0.6875q-1.90625 0 -3.28125 1.3125q-1.375 1.3125 -1.375 4.390625zm21.819702 5.09375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020996 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.297607 4.921875l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0z" fill-rule="nonzero"></path><path fill="#bf9000" d="m550.4829 1121.1864l156.3465 0l0 76.81885l-156.3465 0z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m550.4829 1121.1864l156.3465 0l0 76.81885l-156.3465 0z" fill-rule="nonzero"></path><path fill="#000000" d="m571.6152 1166.5157l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm11.058289 0l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm16.016357 1.75l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm14.031921 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5427246 -10.1875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.5354004 0l0 -8.546875l-1.484375 0l0 -1.3125l1.484375 0l0 -1.046875q0 -0.984375 0.171875 -1.46875q0.234375 -0.65625 0.84375 -1.046875q0.609375 -0.40625 1.703125 -0.40625q0.703125 0 1.5625 0.15625l-0.25 1.46875q-0.515625 -0.09375 -0.984375 -0.09375q-0.765625 0 -1.078125 0.328125q-0.3125 0.3125 -0.3125 1.203125l0 0.90625l1.921875 0l0 1.3125l-1.921875 0l0 8.546875l-1.65625 0zm4.6989746 3.796875l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm21.042664 -3.796875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.2507324 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.75 -0.234375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.094421 5.875l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m490.2467 1036.1575l0 42.51465l138.42523 0l0 42.52478" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m490.2467 1036.1575l0 42.51465l138.42523 0l0 39.097656" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m628.67194 1117.7698l-1.1246338 -1.1246338l1.1246338 3.0898438l1.1245728 -3.0898438z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m767.31494 1036.1575l0 42.51465l-138.64563 0l0 42.52478" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m767.31494 1036.1575l0 42.51465l-138.64563 0l0 39.097656" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m628.6693 1117.7698l-1.1246338 -1.1246338l1.1246338 3.0898438l1.1245728 -3.0898438z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m623.2572 704.6588l4.0 47.905518" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m623.2572 704.6588l3.5007324 41.92633" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m625.11194 746.72253l2.0236206 4.3849487l1.2684326 -4.65979z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m628.6562 1198.0052l0 25.002075l385.45148 0l0 -553.4745l-312.66412 0" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m628.6562 1198.0052l0 25.002075l385.45148 0l0 -553.4745l-309.237 0" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m704.87067 669.53284l1.1245728 -1.1246338l-3.0897827 1.1246338l3.0897827 1.1245728z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m701.4305 651.92975l522.5573 3.0775146l0 -581.44293l-519.1407 0" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m701.4304 651.92975l522.5575 3.0775146l0 -581.44293l-515.71375 0" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m708.2742 73.56431l1.1246338 -1.124588l-3.0897827 1.124588l3.0897827 1.1245804z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m808.0315 611.3517l466.8661 0l0 43.653564l-466.8661 0z" fill-rule="nonzero"></path><path fill="#000000" d="m818.5315 638.2717l0 -13.59375l6.03125 0q1.8125 0 2.75 0.359375q0.953125 0.359375 1.515625 1.296875q0.5625 0.921875 0.5625 2.046875q0 1.453125 -0.9375 2.453125q-0.921875 0.984375 -2.890625 1.25q0.71875 0.34375 1.09375 0.671875q0.78125 0.734375 1.484375 1.8125l2.375 3.703125l-2.265625 0l-1.796875 -2.828125q-0.796875 -1.21875 -1.3125 -1.875q-0.5 -0.65625 -0.90625 -0.90625q-0.40625 -0.265625 -0.8125 -0.359375q-0.3125 -0.078125 -1.015625 -0.078125l-2.078125 0l0 6.046875l-1.796875 0zm1.796875 -7.59375l3.859375 0q1.234375 0 1.921875 -0.25q0.703125 -0.265625 1.0625 -0.828125q0.375 -0.5625 0.375 -1.21875q0 -0.96875 -0.703125 -1.578125q-0.703125 -0.625 -2.21875 -0.625l-4.296875 0l0 4.5zm18.176086 4.421875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.500732 5.875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm9.281921 -6.765625l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm4.1135864 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.9783325 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm15.547546 2.265625l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm6.546875 2.109375l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm10.366638 0l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020386 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm13.215271 5.15625l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm8.261414 -0.234375l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm18.394836 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.078857 5.875l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm10.613586 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm2.265625 -1.3125q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281921 4.921875l0 -9.859375l1.5 0l0 1.390625q0.453125 -0.71875 1.21875 -1.15625q0.78125 -0.453125 1.765625 -0.453125q1.09375 0 1.796875 0.453125q0.703125 0.453125 0.984375 1.28125q1.171875 -1.734375 3.046875 -1.734375q1.46875 0 2.25 0.8125q0.796875 0.8125 0.796875 2.5l0 6.765625l-1.671875 0l0 -6.203125q0 -1.0 -0.15625 -1.4375q-0.15625 -0.453125 -0.59375 -0.71875q-0.421875 -0.265625 -1.0 -0.265625q-1.03125 0 -1.71875 0.6875q-0.6875 0.6875 -0.6875 2.21875l0 5.71875l-1.671875 0l0 -6.40625q0 -1.109375 -0.40625 -1.65625q-0.40625 -0.5625 -1.34375 -0.5625q-0.703125 0 -1.3125 0.375q-0.59375 0.359375 -0.859375 1.078125q-0.265625 0.71875 -0.265625 2.0625l0 5.109375l-1.671875 0zm22.290833 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm14.293396 9.65625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.297607 3.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819214 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.62506104 -0.453125 0.85943604 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.093811 1.296875 -2.718811 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875061 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015686 0.5625 -2.500061 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921936 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.79693604 -0.921875 -1.921936 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047668 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm16.12146 5.875l-3.015625 -9.859375l1.71875 0l1.5625 5.6875l0.59375 2.125q0.03125 -0.15625 0.5 -2.03125l1.578125 -5.78125l1.71875 0l1.46875 5.71875l0.484375 1.890625l0.578125 -1.90625l1.6875 -5.703125l1.625 0l-3.078125 9.859375l-1.734375 0l-1.578125 -5.90625l-0.375 -1.671875l-2.0 7.578125l-1.734375 0zm11.6604 -11.6875l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm7.7855225 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm1.5270996 1.5l0 -13.59375l1.671875 0l0 4.875q1.171875 -1.359375 2.953125 -1.359375q1.09375 0 1.890625 0.4375q0.8125 0.421875 1.15625 1.1875q0.359375 0.765625 0.359375 2.203125l0 6.25l-1.671875 0l0 -6.25q0 -1.25 -0.546875 -1.8125q-0.546875 -0.578125 -1.53125 -0.578125q-0.75 0 -1.40625 0.390625q-0.640625 0.375 -0.921875 1.046875q-0.28125 0.65625 -0.28125 1.8125l0 5.390625l-1.671875 0zm14.887085 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.75 -0.234375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.328125 0l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.015625 -8.75l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.5042725 -4.921875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.281982 4.921875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0zm19.21521 -1.5l0.234375 1.484375q-0.703125 0.140625 -1.265625 0.140625q-0.90625 0 -1.40625 -0.28125q-0.5 -0.296875 -0.703125 -0.75q-0.203125 -0.46875 -0.203125 -1.984375l0 -5.65625l-1.234375 0l0 -1.3125l1.234375 0l0 -2.4375l1.65625 -1.0l0 3.4375l1.6875 0l0 1.3125l-1.6875 0l0 5.75q0 0.71875 0.078125 0.921875q0.09375 0.203125 0.296875 0.328125q0.203125 0.125 0.578125 0.125q0.265625 0 0.734375 -0.078125zm0.9020996 -3.421875q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm9.297607 4.921875l0 -13.59375l1.671875 0l0 7.75l3.953125 -4.015625l2.15625 0l-3.765625 3.65625l4.140625 6.203125l-2.0625 0l-3.25 -5.03125l-1.171875 1.125l0 3.90625l-1.671875 0zm16.0625 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm9.110107 5.875l0 -9.859375l1.5 0l0 1.40625q1.09375 -1.625 3.140625 -1.625q0.890625 0 1.640625 0.328125q0.75 0.3125 1.109375 0.84375q0.375 0.515625 0.53125 1.21875q0.09375 0.46875 0.09375 1.625l0 6.0625l-1.671875 0l0 -6.0q0 -1.015625 -0.203125 -1.515625q-0.1875 -0.515625 -0.6875 -0.8125q-0.5 -0.296875 -1.171875 -0.296875q-1.0625 0 -1.84375 0.671875q-0.765625 0.671875 -0.765625 2.578125l0 5.375l-1.671875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m767.6221 103.74803l179.27557 0l0 43.65355l-179.27557 0z" fill-rule="nonzero"></path><path fill="#000000" d="m778.1221 130.66803l0 -13.59375l6.03125 0q1.8125 0 2.75 0.359375q0.953125 0.359375 1.515625 1.296875q0.5625 0.921875 0.5625 2.046875q0 1.453125 -0.9375 2.453125q-0.921875 0.984375 -2.890625 1.25q0.71875 0.34375 1.09375 0.671875q0.78125 0.734375 1.484375 1.8125l2.375 3.703125l-2.265625 0l-1.796875 -2.828125q-0.796875 -1.21875 -1.3125 -1.875q-0.5 -0.65625 -0.90625 -0.90625q-0.40625 -0.265625 -0.8125 -0.359375q-0.3125 -0.078125 -1.015625 -0.078125l-2.078125 0l0 6.046875l-1.796875 0zm1.796875 -7.59375l3.859375 0q1.234375 0 1.921875 -0.25q0.703125 -0.265625 1.0625 -0.828125q0.375 -0.5625 0.375 -1.21875q0 -0.96875 -0.703125 -1.578125q-0.703125 -0.625 -2.21875 -0.625l-4.296875 0l0 4.5zm18.176025 4.421875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438232 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.375 -1.984375q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735107 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.9069824 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.6657715 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm13.590271 2.015625l1.625 -0.21875q0.0625 1.546875 0.578125 2.125q0.53125 0.578125 1.4375 0.578125q0.6875 0 1.171875 -0.3125q0.5 -0.3125 0.671875 -0.84375q0.1875 -0.53125 0.1875 -1.703125l0 -9.359375l1.8125 0l0 9.265625q0 1.703125 -0.421875 2.640625q-0.40625 0.9375 -1.3125 1.4375q-0.890625 0.484375 -2.09375 0.484375q-1.796875 0 -2.75 -1.03125q-0.9375 -1.03125 -0.90625 -3.0625zm9.640625 -0.515625l1.6875 -0.140625q0.125 1.015625 0.5625 1.671875q0.4375 0.65625 1.359375 1.0625q0.9375 0.40625 2.09375 0.40625q1.03125 0 1.8125 -0.3125q0.796875 -0.3125 1.1875 -0.84375q0.390625 -0.53125 0.390625 -1.15625q0 -0.640625 -0.375 -1.109375q-0.375 -0.484375 -1.234375 -0.8125q-0.546875 -0.21875 -2.421875 -0.65625q-1.875 -0.453125 -2.625 -0.859375q-0.96875 -0.515625 -1.453125 -1.265625q-0.46875 -0.75 -0.46875 -1.6875q0 -1.03125 0.578125 -1.921875q0.59375 -0.90625 1.703125 -1.359375q1.125 -0.46875 2.5 -0.46875q1.515625 0 2.671875 0.484375q1.15625 0.484375 1.765625 1.4375q0.625 0.9375 0.671875 2.140625l-1.71875 0.125q-0.140625 -1.28125 -0.953125 -1.9375q-0.796875 -0.671875 -2.359375 -0.671875q-1.625 0 -2.375 0.609375q-0.75 0.59375 -0.75 1.4375q0 0.734375 0.53125 1.203125q0.515625 0.46875 2.703125 0.96875q2.203125 0.5 3.015625 0.875q1.1875 0.546875 1.75 1.390625q0.578125 0.828125 0.578125 1.921875q0 1.09375 -0.625 2.0625q-0.625 0.953125 -1.796875 1.484375q-1.15625 0.53125 -2.609375 0.53125q-1.84375 0 -3.09375 -0.53125q-1.25 -0.546875 -1.96875 -1.625q-0.703125 -1.078125 -0.734375 -2.453125zm12.5061035 -2.25q0 -3.390625 1.8125 -5.296875q1.828125 -1.921875 4.703125 -1.921875q1.875 0 3.390625 0.90625q1.515625 0.890625 2.296875 2.5q0.796875 1.609375 0.796875 3.65625q0 2.0625 -0.84375 3.703125q-0.828125 1.625 -2.359375 2.46875q-1.53125 0.84375 -3.296875 0.84375q-1.921875 0 -3.4375 -0.921875q-1.5 -0.9375 -2.28125 -2.53125q-0.78125 -1.609375 -0.78125 -3.40625zm1.859375 0.03125q0 2.453125 1.3125 3.875q1.328125 1.40625 3.3125 1.40625q2.03125 0 3.34375 -1.421875q1.3125 -1.4375 1.3125 -4.0625q0 -1.65625 -0.5625 -2.890625q-0.546875 -1.234375 -1.640625 -1.921875q-1.078125 -0.6875 -2.421875 -0.6875q-1.90625 0 -3.28125 1.3125q-1.375 1.3125 -1.375 4.390625zm13.183289 6.59375l0 -13.59375l1.84375 0l7.140625 10.671875l0 -10.671875l1.71875 0l0 13.59375l-1.84375 0l-7.140625 -10.6875l0 10.6875l-1.71875 0z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m529.084 131.11548l-343.0866 -1.102356" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m529.084 131.11548l-337.08667 -1.0830841" fill-rule="evenodd"></path><path fill="#000000" stroke="#000000" stroke-width="1.0" stroke-linecap="butt" d="m192.00266 128.38068l-4.5433807 1.637146l4.5327606 1.6663055z" fill-rule="evenodd"></path><path fill="#000000" fill-opacity="0.0" d="m258.7034 136.56955l156.34647 0l0 70.267715l-156.34647 0z" fill-rule="nonzero"></path><path fill="#000000" d="m269.17215 163.48955l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm16.865448 5.921875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.0632324 4.9375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm5.556427 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm16.75 -0.234375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm13.012146 5.875l5.234375 -13.59375l1.9375 0l5.5625 13.59375l-2.046875 0l-1.59375 -4.125l-5.6875 0l-1.484375 4.125l-1.921875 0zm3.921875 -5.578125l4.609375 0l-1.40625 -3.78125q-0.65625 -1.703125 -0.96875 -2.8125q-0.265625 1.3125 -0.734375 2.59375l-1.5 4.0zm10.021698 5.578125l0 -13.59375l5.125 0q1.359375 0 2.078125 0.125q1.0 0.171875 1.671875 0.640625q0.671875 0.46875 1.078125 1.3125q0.421875 0.84375 0.421875 1.84375q0 1.734375 -1.109375 2.9375q-1.09375 1.203125 -3.984375 1.203125l-3.484375 0l0 5.53125l-1.796875 0zm1.796875 -7.140625l3.515625 0q1.75 0 2.46875 -0.640625q0.734375 -0.65625 0.734375 -1.828125q0 -0.859375 -0.4375 -1.46875q-0.421875 -0.609375 -1.125 -0.796875q-0.453125 -0.125 -1.671875 -0.125l-3.484375 0l0 4.859375zm10.943573 7.140625l0 -13.59375l1.8125 0l0 13.59375l-1.8125 0zm9.835358 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.978302 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438202 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 6.71875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625z" fill-rule="nonzero"></path><path fill="#000000" d="m276.73465 183.88017q-0.828125 0.921875 -1.8125 1.390625q-0.96875 0.453125 -2.09375 0.453125q-2.09375 0 -3.3125 -1.40625q-1.0 -1.15625 -1.0 -2.578125q0 -1.265625 0.8125 -2.28125q0.8125 -1.015625 2.421875 -1.78125q-0.90625 -1.0625 -1.21875 -1.71875q-0.296875 -0.65625 -0.296875 -1.265625q0 -1.234375 0.953125 -2.125q0.953125 -0.90625 2.421875 -0.90625q1.390625 0 2.265625 0.859375q0.890625 0.84375 0.890625 2.046875q0 1.9375 -2.5625 3.3125l2.4375 3.09375q0.421875 -0.8125 0.640625 -1.890625l1.734375 0.375q-0.4375 1.78125 -1.203125 2.9375q0.9375 1.234375 2.125 2.078125l-1.125 1.328125q-1.0 -0.640625 -2.078125 -1.921875zm-3.40625 -7.078125q1.09375 -0.640625 1.40625 -1.125q0.328125 -0.484375 0.328125 -1.0625q0 -0.703125 -0.453125 -1.140625q-0.4375 -0.4375 -1.09375 -0.4375q-0.671875 0 -1.125 0.4375q-0.453125 0.421875 -0.453125 1.0625q0 0.3125 0.15625 0.65625q0.171875 0.34375 0.5 0.734375l0.734375 0.875zm2.359375 5.765625l-3.0625 -3.796875q-1.359375 0.8125 -1.84375 1.5q-0.46875 0.6875 -0.46875 1.375q0 0.8125 0.65625 1.703125q0.671875 0.890625 1.875 0.890625q0.75 0 1.546875 -0.46875q0.8125 -0.46875 1.296875 -1.203125zm17.283142 2.921875l0 -1.25q-0.9375 1.46875 -2.75 1.46875q-1.171875 0 -2.171875 -0.640625q-0.984375 -0.65625 -1.53125 -1.8125q-0.53125 -1.171875 -0.53125 -2.6875q0 -1.46875 0.484375 -2.671875q0.5 -1.203125 1.46875 -1.84375q0.984375 -0.640625 2.203125 -0.640625q0.890625 0 1.578125 0.375q0.703125 0.375 1.140625 0.984375l0 -4.875l1.65625 0l0 13.59375l-1.546875 0zm-5.28125 -4.921875q0 1.890625 0.796875 2.828125q0.8125 0.9375 1.890625 0.9375q1.09375 0 1.859375 -0.890625q0.765625 -0.890625 0.765625 -2.734375q0 -2.015625 -0.78125 -2.953125q-0.78125 -0.953125 -1.921875 -0.953125q-1.109375 0 -1.859375 0.90625q-0.75 0.90625 -0.75 2.859375zm9.281952 -6.765625l0 -1.90625l1.671875 0l0 1.90625l-1.671875 0zm0 11.6875l0 -9.859375l1.671875 0l0 9.859375l-1.671875 0zm3.4573364 -2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm10.0 6.71875l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm8.828827 4.875l0 -13.59375l1.671875 0l0 13.59375l-1.671875 0zm10.613586 -1.21875q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm4.000702 8.734375l-0.171875 -1.5625q0.546875 0.140625 0.953125 0.140625q0.546875 0 0.875 -0.1875q0.34375 -0.1875 0.5625 -0.515625q0.15625 -0.25 0.5 -1.25q0.046875 -0.140625 0.15625 -0.40625l-3.734375 -9.875l1.796875 0l2.046875 5.71875q0.40625 1.078125 0.71875 2.28125q0.28125 -1.15625 0.6875 -2.25l2.09375 -5.75l1.671875 0l-3.75 10.03125q-0.59375 1.625 -0.9375 2.234375q-0.4375 0.828125 -1.015625 1.203125q-0.578125 0.390625 -1.375 0.390625q-0.484375 0 -1.078125 -0.203125zm14.589569 -0.015625l0 -13.640625l1.53125 0l0 1.28125q0.53125 -0.75 1.203125 -1.125q0.6875 -0.375 1.640625 -0.375q1.265625 0 2.234375 0.65625q0.96875 0.640625 1.453125 1.828125q0.5 1.1875 0.5 2.59375q0 1.515625 -0.546875 2.734375q-0.546875 1.203125 -1.578125 1.84375q-1.03125 0.640625 -2.171875 0.640625q-0.84375 0 -1.515625 -0.34375q-0.65625 -0.359375 -1.078125 -0.890625l0 4.796875l-1.671875 0zm1.515625 -8.65625q0 1.90625 0.765625 2.8125q0.78125 0.90625 1.875 0.90625q1.109375 0 1.890625 -0.9375q0.796875 -0.9375 0.796875 -2.921875q0 -1.875 -0.78125 -2.8125q-0.765625 -0.9375 -1.84375 -0.9375q-1.0625 0 -1.890625 1.0q-0.8125 1.0 -0.8125 2.890625zm15.297577 3.65625q-0.9375 0.796875 -1.796875 1.125q-0.859375 0.3125 -1.84375 0.3125q-1.609375 0 -2.484375 -0.78125q-0.875 -0.796875 -0.875 -2.03125q0 -0.734375 0.328125 -1.328125q0.328125 -0.59375 0.859375 -0.953125q0.53125 -0.359375 1.203125 -0.546875q0.5 -0.140625 1.484375 -0.25q2.03125 -0.25 2.984375 -0.578125q0 -0.34375 0 -0.4375q0 -1.015625 -0.46875 -1.4375q-0.640625 -0.5625 -1.90625 -0.5625q-1.171875 0 -1.734375 0.40625q-0.5625 0.40625 -0.828125 1.46875l-1.640625 -0.234375q0.234375 -1.046875 0.734375 -1.6875q0.515625 -0.640625 1.46875 -0.984375q0.96875 -0.359375 2.25 -0.359375q1.265625 0 2.046875 0.296875q0.78125 0.296875 1.15625 0.75q0.375 0.453125 0.515625 1.140625q0.09375 0.421875 0.09375 1.53125l0 2.234375q0 2.328125 0.09375 2.953125q0.109375 0.609375 0.4375 1.171875l-1.75 0q-0.265625 -0.515625 -0.328125 -1.21875zm-0.140625 -3.71875q-0.90625 0.359375 -2.734375 0.625q-1.03125 0.140625 -1.453125 0.328125q-0.421875 0.1875 -0.65625 0.546875q-0.234375 0.359375 -0.234375 0.796875q0 0.671875 0.5 1.125q0.515625 0.4375 1.484375 0.4375q0.96875 0 1.71875 -0.421875q0.75 -0.4375 1.109375 -1.15625q0.265625 -0.578125 0.265625 -1.671875l0 -0.609375zm3.7819824 5.75l1.609375 0.25q0.109375 0.75 0.578125 1.09375q0.609375 0.453125 1.6875 0.453125q1.171875 0 1.796875 -0.46875q0.625 -0.453125 0.859375 -1.28125q0.125 -0.515625 0.109375 -2.15625q-1.09375 1.296875 -2.71875 1.296875q-2.03125 0 -3.15625 -1.46875q-1.109375 -1.46875 -1.109375 -3.515625q0 -1.40625 0.515625 -2.59375q0.515625 -1.203125 1.484375 -1.84375q0.96875 -0.65625 2.265625 -0.65625q1.75 0 2.875 1.40625l0 -1.1875l1.546875 0l0 8.515625q0 2.3125 -0.46875 3.265625q-0.46875 0.96875 -1.484375 1.515625q-1.015625 0.5625 -2.5 0.5625q-1.765625 0 -2.859375 -0.796875q-1.078125 -0.796875 -1.03125 -2.390625zm1.375 -5.921875q0 1.953125 0.765625 2.84375q0.78125 0.890625 1.9375 0.890625q1.140625 0 1.921875 -0.890625q0.78125 -0.890625 0.78125 -2.78125q0 -1.8125 -0.8125 -2.71875q-0.796875 -0.921875 -1.921875 -0.921875q-1.109375 0 -1.890625 0.90625q-0.78125 0.890625 -0.78125 2.671875zm16.047577 1.9375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#ffffff" d="m94.25984 75.59843l0 0c0 -12.054596 10.597107 -21.826775 23.669289 -21.826775l0 0c13.072197 0 23.669289 9.772179 23.669289 21.826775l0 0c0 12.054588 -10.597092 21.826767 -23.669289 21.826767l0 0c-13.072182 0 -23.669289 -9.772179 -23.669289 -21.826767z" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m94.25984 75.59843l0 0c0 -12.054596 10.597107 -21.826775 23.669289 -21.826775l0 0c13.072197 0 23.669289 9.772179 23.669289 21.826775l0 0c0 12.054588 -10.597092 21.826767 -23.669289 21.826767l0 0c-13.072182 0 -23.669289 -9.772179 -23.669289 -21.826767z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m117.92913 97.42519l1.1653595 119.55906" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m117.92913 97.42519l1.1653595 119.55906" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m117.92913 128.50131l29.574806 42.48819" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m117.92913 128.50131l29.574806 42.48819" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m91.50131 170.50131l26.425194 -41.07086" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m91.50131 170.50131l26.425194 -41.07086" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m235.77428 40.0l179.27559 0l0 48.0l-179.27559 0z" fill-rule="nonzero"></path><path fill="#000000" d="m273.33563 65.59187l0 -1.609375l5.765625 0l0 5.046875q-1.328125 1.0625 -2.75 1.59375q-1.40625 0.53125 -2.890625 0.53125q-2.0 0 -3.640625 -0.859375q-1.625 -0.859375 -2.46875 -2.484375q-0.828125 -1.625 -0.828125 -3.625q0 -1.984375 0.828125 -3.703125q0.828125 -1.71875 2.390625 -2.546875q1.5625 -0.84375 3.59375 -0.84375q1.46875 0 2.65625 0.484375q1.203125 0.46875 1.875 1.328125q0.671875 0.84375 1.03125 2.21875l-1.625 0.4375q-0.3125 -1.03125 -0.765625 -1.625q-0.453125 -0.59375 -1.296875 -0.953125q-0.84375 -0.359375 -1.875 -0.359375q-1.234375 0 -2.140625 0.375q-0.890625 0.375 -1.453125 1.0q-0.546875 0.609375 -0.84375 1.34375q-0.53125 1.25 -0.53125 2.734375q0 1.8125 0.625 3.046875q0.640625 1.21875 1.828125 1.8125q1.203125 0.59375 2.546875 0.59375q1.171875 0 2.28125 -0.453125q1.109375 -0.453125 1.6875 -0.953125l0 -2.53125l-4.0 0zm8.183289 5.328125l0 -13.59375l9.84375 0l0 1.59375l-8.046875 0l0 4.171875l7.53125 0l0 1.59375l-7.53125 0l0 4.625l8.359375 0l0 1.609375l-10.15625 0zm15.865448 0l0 -12.0l-4.46875 0l0 -1.59375l10.765625 0l0 1.59375l-4.5 0l0 12.0l-1.796875 0zm11.65741 0.234375l3.9375 -14.0625l1.34375 0l-3.9375 14.0625l-1.34375 0zm6.417694 -0.234375l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.978302 -3.171875l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875zm8.438202 2.9375l1.65625 -0.265625q0.140625 1.0 0.765625 1.53125q0.640625 0.515625 1.78125 0.515625q1.15625 0 1.703125 -0.46875q0.5625 -0.46875 0.5625 -1.09375q0 -0.5625 -0.484375 -0.890625q-0.34375 -0.21875 -1.703125 -0.5625q-1.84375 -0.46875 -2.5625 -0.796875q-0.703125 -0.34375 -1.078125 -0.9375q-0.359375 -0.609375 -0.359375 -1.328125q0 -0.65625 0.296875 -1.21875q0.3125 -0.5625 0.828125 -0.9375q0.390625 -0.28125 1.0625 -0.484375q0.671875 -0.203125 1.4375 -0.203125q1.171875 0 2.046875 0.34375q0.875 0.328125 1.28125 0.90625q0.421875 0.5625 0.578125 1.515625l-1.625 0.21875q-0.109375 -0.75 -0.65625 -1.171875q-0.53125 -0.4375 -1.5 -0.4375q-1.15625 0 -1.640625 0.390625q-0.484375 0.375 -0.484375 0.875q0 0.328125 0.203125 0.59375q0.203125 0.265625 0.640625 0.4375q0.25 0.09375 1.46875 0.4375q1.765625 0.46875 2.46875 0.765625q0.703125 0.296875 1.09375 0.875q0.40625 0.578125 0.40625 1.4375q0 0.828125 -0.484375 1.578125q-0.484375 0.734375 -1.40625 1.140625q-0.921875 0.390625 -2.078125 0.390625q-1.921875 0 -2.9375 -0.796875q-1.0 -0.796875 -1.28125 -2.359375zm9.375 -1.984375q0 -2.734375 1.53125 -4.0625q1.265625 -1.09375 3.09375 -1.09375q2.03125 0 3.3125 1.34375q1.296875 1.328125 1.296875 3.671875q0 1.90625 -0.578125 3.0q-0.5625 1.078125 -1.65625 1.6875q-1.078125 0.59375 -2.375 0.59375q-2.0625 0 -3.34375 -1.328125q-1.28125 -1.328125 -1.28125 -3.8125zm1.71875 0q0 1.890625 0.828125 2.828125q0.828125 0.9375 2.078125 0.9375q1.25 0 2.0625 -0.9375q0.828125 -0.953125 0.828125 -2.890625q0 -1.828125 -0.828125 -2.765625q-0.828125 -0.9375 -2.0625 -0.9375q-1.25 0 -2.078125 0.9375q-0.828125 0.9375 -0.828125 2.828125zm15.735107 4.921875l0 -1.453125q-1.140625 1.671875 -3.125 1.671875q-0.859375 0 -1.625 -0.328125q-0.75 -0.34375 -1.125 -0.84375q-0.359375 -0.5 -0.515625 -1.234375q-0.09375 -0.5 -0.09375 -1.5625l0 -6.109375l1.671875 0l0 5.46875q0 1.3125 0.09375 1.765625q0.15625 0.65625 0.671875 1.03125q0.515625 0.375 1.265625 0.375q0.75 0 1.40625 -0.375q0.65625 -0.390625 0.921875 -1.046875q0.28125 -0.671875 0.28125 -1.9375l0 -5.28125l1.671875 0l0 9.859375l-1.5 0zm3.906952 0l0 -9.859375l1.5 0l0 1.5q0.578125 -1.046875 1.0625 -1.375q0.484375 -0.34375 1.078125 -0.34375q0.84375 0 1.71875 0.546875l-0.578125 1.546875q-0.609375 -0.359375 -1.234375 -0.359375q-0.546875 0 -0.984375 0.328125q-0.421875 0.328125 -0.609375 0.90625q-0.28125 0.890625 -0.28125 1.953125l0 5.15625l-1.671875 0zm12.665802 -3.609375l1.640625 0.21875q-0.265625 1.6875 -1.375 2.65625q-1.109375 0.953125 -2.734375 0.953125q-2.015625 0 -3.25 -1.3125q-1.21875 -1.328125 -1.21875 -3.796875q0 -1.59375 0.515625 -2.78125q0.53125 -1.203125 1.609375 -1.796875q1.09375 -0.609375 2.359375 -0.609375q1.609375 0 2.625 0.8125q1.015625 0.8125 1.3125 2.3125l-1.625 0.25q-0.234375 -1.0 -0.828125 -1.5q-0.59375 -0.5 -1.421875 -0.5q-1.265625 0 -2.0625 0.90625q-0.78125 0.90625 -0.78125 2.859375q0 1.984375 0.765625 2.890625q0.765625 0.890625 1.984375 0.890625q0.984375 0 1.640625 -0.59375q0.65625 -0.609375 0.84375 -1.859375zm9.640625 0.4375l1.71875 0.21875q-0.40625 1.5 -1.515625 2.34375q-1.09375 0.828125 -2.8125 0.828125q-2.15625 0 -3.421875 -1.328125q-1.265625 -1.328125 -1.265625 -3.734375q0 -2.484375 1.265625 -3.859375q1.28125 -1.375 3.328125 -1.375q1.984375 0 3.234375 1.34375q1.25 1.34375 1.25 3.796875q0 0.140625 -0.015625 0.4375l-7.34375 0q0.09375 1.625 0.921875 2.484375q0.828125 0.859375 2.0625 0.859375q0.90625 0 1.546875 -0.46875q0.65625 -0.484375 1.046875 -1.546875zm-5.484375 -2.703125l5.5 0q-0.109375 -1.234375 -0.625 -1.859375q-0.796875 -0.96875 -2.078125 -0.96875q-1.140625 0 -1.9375 0.78125q-0.78125 0.765625 -0.859375 2.046875z" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m119.125984 215.50131l-38.58268 53.07086" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m119.125984 215.50131l-38.58268 53.07086" fill-rule="nonzero"></path><path fill="#000000" fill-opacity="0.0" d="m119.62467 215.50131l42.99212 58.992126" fill-rule="nonzero"></path><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m119.62467 215.50131l42.99212 58.992126" fill-rule="nonzero"></path></g></svg>
+
---
layout: default
navsection: installguide
-title: Crunch v2 SLURM prerequisites
+title: Containers API SLURM prerequisites
...
-Crunch v2 containers can be dispatched to a SLURM cluster. The dispatcher sends work to the cluster using SLURM's @sbatch@ command, so it works in a variety of SLURM configurations.
+Containers can be dispatched to a SLURM cluster. The dispatcher sends work to the cluster using SLURM's @sbatch@ command, so it works in a variety of SLURM configurations.
In order to run containers, you must run the dispatcher as a user that has permission to set up FUSE mounts and run Docker containers on each compute node. This install guide refers to this user as the @crunch@ user. We recommend you create this user on each compute node with the same UID and GID, and add it to the @fuse@ and @docker@ system groups to grant it the necessary permissions. However, you can run the dispatcher under any account with sufficient permissions across the cluster.
</code></pre>
</notextile>
-{% assign railscmd = "bundle exec ./script/get_anonymous_user_token.rb" %}
+{% assign railscmd = "bundle exec ./script/get_anonymous_user_token.rb --get" %}
{% assign railsout = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" %}
If you intend to use Keep-web to serve public data to anonymous clients, configure it with an anonymous token. You can use the same one you used when you set up your Keepproxy server, or use the following command on the <strong>API server</strong> to create another. {% include 'install_rails_command' %}
h3. Create an API token for the Keepproxy server
-{% assign railscmd = "bundle exec ./script/get_anonymous_user_token.rb" %}
+{% assign railscmd = "bundle exec ./script/get_anonymous_user_token.rb --get" %}
{% assign railsout = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" %}
The Keepproxy server needs a token to talk to the API server. On the <strong>API server</strong>, use the following command to create the token. {% include 'install_rails_command' %}
--- /dev/null
+---
+layout: default
+navsection: installguide
+title: Install the websocket server
+...
+
+{% include 'notebox_begin_warning' %}
+
+This websocket server is an alternative to the puma server that comes with the API server. It is available as an *experimental pre-release* and is not recommended for production sites.
+
+{% include 'notebox_end' %}
+
+The arvados-ws server provides event notifications to websocket clients. It can be installed anywhere with access to Postgres database and the Arvados API server, typically behind a web proxy that provides SSL support. See the "godoc page":http://godoc.org/github.com/curoverse/arvados/services/keep-web for additional information.
+
+By convention, we use the following hostname for the websocket service.
+
+<notextile>
+<pre><code>ws.<span class="userinput">uuid_prefix.your.domain</span></code></pre>
+</notextile>
+
+The above hostname should resolve from anywhere on the internet.
+
+h2. Install arvados-ws
+
+Typically arvados-ws runs on the same host as the API server.
+
+On Debian-based systems:
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo apt-get install arvados-ws</span>
+</code></pre>
+</notextile>
+
+On Red Hat-based systems:
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo yum install arvados-ws</span>
+</code></pre>
+</notextile>
+
+Verify that @arvados-ws@ is functional:
+
+<notextile>
+<pre><code>~$ <span class="userinput">arvados-ws -h</span>
+Usage of arvados-ws:
+ -config path
+ path to config file (default "/etc/arvados/ws/ws.yml")
+ -dump-config
+ show current configuration and exit
+</code></pre>
+</notextile>
+
+h3. Create a configuration file
+
+Create @/etc/arvados/ws/ws.yml@ using the following template. Replace @xxxxxxxx@ with the "password you generated during database setup":install-postgresql.html#api.
+
+<notextile>
+<pre><code>Client:
+ APIHost: <span class="userinput">uuid_prefix.your.domain</span>:443
+Listen: ":<span class="userinput">9003</span>"
+Postgres:
+ dbname: arvados_production
+ host: localhost
+ password: <span class="userinput">xxxxxxxx</span>
+ user: arvados
+</code></pre>
+</notextile>
+
+h3. Start the service (option 1: systemd)
+
+If your system does not use systemd, skip this section and follow the "runit instructions":#runit instead.
+
+If your system uses systemd, the arvados-ws service should already be set up. Start it and check its status:
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo systemctl restart arvados-ws</span>
+~$ <span class="userinput">sudo systemctl status arvados-ws</span>
+● arvados-ws.service - Arvados websocket server
+ Loaded: loaded (/lib/systemd/system/arvados-ws.service; enabled)
+ Active: active (running) since Tue 2016-12-06 11:20:48 EST; 10s ago
+ Docs: https://doc.arvados.org/
+ Main PID: 9421 (arvados-ws)
+ CGroup: /system.slice/arvados-ws.service
+ └─9421 /usr/bin/arvados-ws
+
+Dec 06 11:20:48 zzzzz arvados-ws[9421]: {"level":"info","msg":"started","time":"2016-12-06T11:20:48.207617188-05:00"}
+Dec 06 11:20:48 zzzzz arvados-ws[9421]: {"Listen":":9003","level":"info","msg":"listening","time":"2016-12-06T11:20:48.244956506-05:00"}
+Dec 06 11:20:48 zzzzz systemd[1]: Started Arvados websocket server.
+</code></pre>
+</notextile>
+
+If it is not running, use @journalctl@ to check logs for errors:
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo journalctl -n10 -u arvados-ws</span>
+...
+Dec 06 11:12:48 zzzzz systemd[1]: Starting Arvados websocket server...
+Dec 06 11:12:48 zzzzz arvados-ws[8918]: {"level":"info","msg":"started","time":"2016-12-06T11:12:48.030496636-05:00"}
+Dec 06 11:12:48 zzzzz arvados-ws[8918]: {"error":"pq: password authentication failed for user \"arvados\"","level":"fatal","msg":"db.Ping failed","time":"2016-12-06T11:12:48.058206400-05:00"}
+</code></pre>
+</notextile>
+
+Skip ahead to "confirm the service is working":#confirm.
+
+h3(#runit). Start the service (option 2: runit)
+
+Install runit to supervise the arvados-ws daemon. {% include 'install_runit' %}
+
+Create a supervised service.
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo mkdir /etc/service/arvados-ws</span>
+~$ <span class="userinput">cd /etc/service/arvados-ws</span>
+~$ <span class="userinput">sudo mkdir log log/main</span>
+~$ <span class="userinput">printf '#!/bin/sh\nexec arvados-ws 2>&1\n' | sudo tee run</span>
+~$ <span class="userinput">printf '#!/bin/sh\nexec svlogd main\n' | sudo tee log/run</span>
+~$ <span class="userinput">sudo chmod +x run log/run</span>
+~$ <span class="userinput">sudo sv exit .</span>
+~$ <span class="userinput">cd -</span>
+</code></pre>
+</notextile>
+
+Use @sv stat@ and check the log file to verify the service is running.
+
+<notextile>
+<pre><code>~$ <span class="userinput">sudo sv stat /etc/service/arvados-ws</span>
+run: /etc/service/arvados-ws: (pid 12520) 2s; run: log: (pid 12519) 2s
+~$ <span class="userinput">tail /etc/service/arvados-ws/log/main/current</span>
+{"level":"info","msg":"started","time":"2016-12-06T11:56:20.669171449-05:00"}
+{"Listen":":9003","level":"info","msg":"listening","time":"2016-12-06T11:56:20.708847627-05:00"}
+</code></pre>
+</notextile>
+
+h3(#confirm). Confirm the service is working
+
+Confirm the service is listening on its assigned port and responding to requests.
+
+<notextile>
+<pre><code>~$ <span class="userinput">curl http://0.0.0.0:<b>9003</b>/status.json</span>
+{"Clients":1}
+</code></pre>
+</notextile>
+
+h3. Set up a reverse proxy with SSL support
+
+The arvados-ws service will be accessible from anywhere on the internet, so we recommend using SSL for transport encryption.
+
+This is best achieved by putting a reverse proxy with SSL support in front of arvados-ws, running on port 443 and passing requests to arvados-ws on port 9003 (or whatever port you chose in your configuration file).
+
+For example, using Nginx:
+
+<notextile><pre>
+upstream arvados-ws {
+ server 127.0.0.1:<span class="userinput">9003</span>;
+}
+
+server {
+ listen <span class="userinput">[your public IP address]</span>:443 ssl;
+ server_name ws.<span class="userinput">uuid_prefix.your.domain</span>;
+
+ proxy_connect_timeout 90s;
+ proxy_read_timeout 300s;
+
+ ssl on;
+ ssl_certificate <span class="userinput"/>YOUR/PATH/TO/cert.pem</span>;
+ ssl_certificate_key <span class="userinput"/>YOUR/PATH/TO/cert.key</span>;
+
+ location / {
+ proxy_pass http://arvados-ws;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+}
+</pre></notextile>
+
+If Nginx is already configured to proxy @ws@ requests to puma, move that configuration out of the way or change its @server_name@ so it doesn't conflict.
+
+h3. Update API server configuration
+
+Ensure the websocket server address is correct in the API server configuration file @/etc/arvados/api/application.yml@.
+
+<notextile>
+<pre><code>websocket_address: wss://ws.<span class="userinput">uuid_prefix.your.domain</span>/websocket
+</code></pre>
+</notextile>
+
+Restart Nginx to reload the API server configuration.
+
+<notextile>
+<pre><code>$ sudo nginx -s reload</span>
+</code></pre>
+</notextile>
+
+h3. Verify DNS and proxy setup
+
+Use a host elsewhere on the Internet to confirm that your DNS, proxy, and SSL are configured correctly.
+
+<notextile>
+<pre><code>$ <span class="userinput">curl https://ws.<b>uuid_prefix.your.domain</b>/status.json</span>
+{"Clients":1}
+</code></pre>
+</notextile>
navsection: sdk
navmenu: CLI
title: "Installation"
-
...
Arvados CLI tools are written in Ruby and Python. To use the @arv@ command, you can either install the @arvados-cli@ gem via RubyGems or build and install the package from source. The @arv@ command also relies on other Arvados tools. To get those, install the @arvados-python-client@ and @arvados-cwl-runner@ packages, either from PyPI or source.
--- /dev/null
+---
+layout: default
+navsection: sdk
+navmenu: Python
+title: Examples
+...
+
+See "Arvados GoDoc":https://godoc.org/git.curoverse.com/arvados.git/sdk/go for detailed documentation.
+
+In these examples, the site prefix is @aaaaa@.
+
+h2. Initialize SDK
+
+<pre>
+import (
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
+}
+
+func main() {
+ arv, err := arvadosclient.MakeArvadosClient()
+ if err != nil {
+ log.Fatalf("Error setting up arvados client %s", err.Error())
+ }
+}
+</pre>
+
+h2. create
+
+<pre>
+ var collection arvados.Collection
+ err := api.Create("collections", Dict{"collection": Dict{"name": "create example"}}, &collection)
+</pre>
+
+h2. delete
+
+<pre>
+ var collection arvados.Collection
+ err := api.Delete("collections", "aaaaa-4zz18-ccccccccccccccc", Dict{}, &collection)
+</pre>
+
+h2. get
+
+<pre>
+ var collection arvados.Collection
+ err := api.Get("collections", "aaaaa-4zz18-ccccccccccccccc", Dict{}, &collection)
+</pre>
+
+h2. list
+
+<pre>
+ var collection arvados.Collection
+ err := api.List("collections", Dict{}, &collection)
+</pre>
+
+h2. update
+
+<pre>
+ var collection arvados.Collection
+ err := api.Update("collections", "aaaaa-4zz18-ccccccccccccccc", Dict{"collection": Dict{"name": "update example"}}, &collection)
+</pre>
+
+h2. Get current user
+
+<pre>
+ var user arvados.User
+ err := api.Get("users", "current", Dict{}, &user)
+</pre>
+
+h2. Example program
+
+You can save this source as a .go file and run it:
+
+<notextile>{% code 'example_sdk_go' as go %}</notextile>
+
+A few more usage examples can be found in the "services/keepproxy":https://dev.arvados.org/projects/arvados/repository/revisions/master/show/services/keepproxy and "sdk/go/keepclient":https://dev.arvados.org/projects/arvados/repository/revisions/master/show/sdk/go/keepclient directories in the arvados source tree.
layout: default
navsection: sdk
navmenu: Go
-title: "Go SDK"
-
+title: "Installation"
...
The Go ("Golang":http://golang.org) SDK provides a generic set of wrappers so you can make API calls easily.
+See "Arvados GoDoc":https://godoc.org/git.curoverse.com/arvados.git/sdk/go for detailed documentation.
+
h3. Installation
-You don't need to install anything. Just import the client like this. The go tools will fetch the relevant code and dependencies for you.
+Use @go get git.curoverse.com/arvados.git/sdk/go/arvadosclient@. The go tools will fetch the relevant code and dependencies for you.
<notextile>{% code 'example_sdk_go_imports' as go %}</notextile>
If you need pre-release client code, you can use the latest version from the repo by following "these instructions.":https://dev.arvados.org/projects/arvados/wiki/Go#Using-Go-with-Arvados
-
-h3. Example
-
-You can save this source as a .go file and run it:
-
-<notextile>{% code 'example_sdk_go' as go %}</notextile>
-
-A few more usage examples can be found in the "services/keepproxy":https://dev.arvados.org/projects/arvados/repository/revisions/master/show/services/keepproxy and "sdk/go/keepclient":https://dev.arvados.org/projects/arvados/repository/revisions/master/show/sdk/go/keepclient directories in the arvados source tree.
---
layout: default
navsection: sdk
-title: "Arvados SDK Reference"
+title: "SDK Reference"
...
-This section documents how to access the Arvados API and Keep using various programming languages.
+This section documents language bindings for the "Arvados API":{{site.baseurl}}/api and Keep that are available for various programming languages. Not all features are available in every SDK. The most complete SDK is the Python SDK. Note that this section only gives a high level overview of each SDK. Consult the "Arvados API":{{site.baseurl}}/api section for detailed documentation about Arvados API calls available on each resource.
* "Python SDK":{{site.baseurl}}/sdk/python/sdk-python.html
+* "Command line SDK":{{site.baseurl}}/sdk/cli/install.html ("arv")
+* "Go SDK":{{site.baseurl}}/sdk/go/index.html
* "Perl SDK":{{site.baseurl}}/sdk/perl/index.html
* "Ruby SDK":{{site.baseurl}}/sdk/ruby/index.html
* "Java SDK":{{site.baseurl}}/sdk/java/index.html
-* "Go SDK":{{site.baseurl}}/sdk/go/index.html
-* "Command line SDK":{{site.baseurl}}/sdk/cli/index.html ("arv")
-
-SDKs not yet implemented:
-* Rails SDK: Workbench uses an ActiveRecord-like interface to Arvados. This hasn't yet been extracted from Workbench and packaged as a gem.
-* R: We plan to support this, but it has not been implemented yet.
+Many Arvados Workbench pages, under the the *Advanced* tab, provide examples of API and SDK use for accessing the current resource .
--- /dev/null
+---
+layout: default
+navsection: sdk
+navmenu: Java
+title: "Examples"
+...
+
+h2. Initialize SDK
+
+<pre>
+import org.arvados.sdk.Arvados;
+</pre>
+
+<pre>
+ String apiName = "arvados";
+ String apiVersion = "v1";
+
+ Arvados arv = new Arvados(apiName, apiVersion);
+</pre>
+
+h2. create
+
+<pre>
+ Map<String, String> collection = new HashMap<String, String>();
+ collection.put("name", "create example");
+
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("collection", collection);
+ Map response = arv.call("collections", "create", params);
+</pre>
+
+h2. delete
+
+<pre>
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("uuid", uuid);
+ Map response = arv.call("collections", "delete", params);
+</pre>
+
+h2. get
+
+<pre>
+ params = new HashMap<String, Object>();
+ params.put("uuid", userUuid);
+ Map response = arv.call("users", "get", params);
+</pre>
+
+h2. list
+
+<pre>
+ Map<String, Object> params = new HashMap<String, Object>();
+ Map response = arv.call("users", "list", params);
+
+ // get uuid of the first user from the response
+ List items = (List)response.get("items");
+
+ Map firstUser = (Map)items.get(0);
+ String userUuid = (String)firstUser.get("uuid");
+</pre>
+
+h2. update
+
+<pre>
+ Map<String, String> collection = new HashMap<String, String>();
+ collection.put("name", "update example");
+
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("uuid", uuid);
+ params.put("collection", collection);
+ Map response = arv.call("collections", "update", params);
+</pre>
+
+h2. Get current user
+
+<pre>
+ Map<String, Object> params = new HashMap<String, Object>();
+ Map response = arv.call("users", "current", params);
+</pre>
layout: default
navsection: sdk
navmenu: Java
-title: "Java SDK"
-
+title: "Installation"
...
The Java SDK provides a generic set of wrappers so you can make API calls in java.
h3. Introdution
* The Java SDK requires Java 6 or later
-
+
* The Java SDK is implemented as a maven project. Hence, you would need a working
maven environment to be able to build the source code. If you do not have maven setup,
-you may find the "Maven in 5 Minutes":http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html link useful.
+you may find the "Maven in 5 Minutes":http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html link useful.
* In this document $ARVADOS_HOME is used to refer to the directory where
arvados code is cloned in your system. For ex: $ARVADOS_HOME = $HOME/arvados
</notextile>
* Please see "api-tokens":{{site.baseurl}}/user/reference/api-tokens.html for full details.
-
+
h3. Building the Arvados SDK
<pre>
In Eclipse IDE:
Window -> Preferences -> Java -> Build Path -> Classpath Variables
- Click on the "New..." button and add a new
+ Click on the "New..." button and add a new
M2_REPO variable and set it to your local Maven repository
</pre>
</notextile>
--- /dev/null
+---
+layout: default
+navsection: sdk
+navmenu: Perl
+title: "Examples"
+...
+
+h2. Initialize SDK
+
+Set up an API client user agent:
+
+<notextile>
+<pre><code class="userinput">
+use Arvados;
+my $arv = Arvados->new('apiVersion' => 'v1');
+</code></pre>
+</notextile>
+
+The SDK retrieves the list of API methods from the server at run time. Therefore, the set of available methods is determined by the server version rather than the SDK version.
+
+h2. create
+
+Create an object:
+
+<notextile>
+<pre><code class="userinput">my $test_link = $arv->{'links'}->{'create'}->execute('link' => { 'link_class' => 'test', 'name' => 'test' });
+</code></pre>
+</notextile>
+
+h2. delete
+
+<notextile>
+<pre><code class="userinput">my $some_user = $arv->{'collections'}->{'get'}->execute('uuid' => $collection_uuid);
+</code></pre>
+</notextile>
+
+h2. get
+
+Retrieve an object by ID:
+
+<notextile>
+<pre><code class="userinput">my $some_user = $arv->{'users'}->{'get'}->execute('uuid' => $current_user_uuid);
+</code></pre>
+</notextile>
+
+Get the UUID of an object that was retrieved using the SDK:
+
+<notextile>
+<pre><code class="userinput">my $current_user_uuid = $current_user->{'uuid'}
+</code></pre>
+</notextile>
+
+h2. list
+
+Get a list of objects:
+
+<notextile>
+<pre><code class="userinput">my $repos = $arv->{'repositories'}->{'list'}->execute;
+print ("UUID of first repo returned is ", $repos->{'items'}->[0], "\n");
+</code></pre>
+</notextile>
+
+h2. update
+
+Update an object:
+
+<notextile>
+<pre><code class="userinput">my $test_link = $arv->{'links'}->{'update'}->execute(
+ 'uuid' => $test_link->{'uuid'},
+ 'link' => { 'properties' => { 'foo' => 'bar' } });
+</code></pre>
+</notextile>
+
+h2. Get current user
+
+Get the User object for the current user:
+
+<notextile>
+<pre><code class="userinput">my $current_user = $arv->{'users'}->{'current'}->execute;
+</code></pre>
+</notextile>
layout: default
navsection: sdk
navmenu: Perl
-title: "Perl SDK"
-
+title: "Installation"
...
The Perl SDK provides a generic set of wrappers so you can make API calls easily.
arvados.v1.users.current.full_name = 'Your Name'
</pre>
</notextile>
-
-h3. Examples
-
-Set up an API client user agent:
-
-<notextile>
-<pre><code class="userinput">my $arv = Arvados->new('apiVersion' => 'v1');
-</code></pre>
-</notextile>
-
-Get the User object for the current user:
-
-<notextile>
-<pre><code class="userinput">my $current_user = $arv->{'users'}->{'current'}->execute;
-</code></pre>
-</notextile>
-
-Get the UUID of an object that was retrieved using the SDK:
-
-<notextile>
-<pre><code class="userinput">my $current_user_uuid = $current_user->{'uuid'}
-</code></pre>
-</notextile>
-
-Retrieve an object by ID:
-
-<notextile>
-<pre><code class="userinput">my $some_user = $arv->{'users'}->{'get'}->execute('uuid' => $current_user_uuid);
-</code></pre>
-</notextile>
-
-Create an object:
-
-<notextile>
-<pre><code class="userinput">my $test_link = $arv->{'links'}->{'create'}->execute('link' => { 'link_class' => 'test', 'name' => 'test' });
-</code></pre>
-</notextile>
-
-Update an object:
-
-<notextile>
-<pre><code class="userinput">my $test_link = $arv->{'links'}->{'update'}->execute(
- 'uuid' => $test_link->{'uuid'},
- 'link' => { 'properties' => { 'foo' => 'bar' } });
-</code></pre>
-</notextile>
-
-Get a list of objects:
-
-<notextile>
-<pre><code class="userinput">my $repos = $arv->{'repositories'}->{'list'}->execute;
-print ("UUID of first repo returned is ", $repos->{'items'}->[0], "\n");
-</code></pre>
-</notextile>
-
-The SDK retrieves the list of API methods from the server at run time. Therefore, the set of available methods is determined by the server version rather than the SDK version.
title: Subscribing to events
...
-Arvados applications can subscribe to a live event stream from the database. Events are described in the "Log record schema.":{{site.baseurl}}/api/schema/Log.html
+Arvados applications can subscribe to a live event stream from the database. Events are described in the "Log resource.":{{site.baseurl}}/api/methods/logs.html
<notextile>
{% code 'events_py' as python %}
--- /dev/null
+---
+layout: default
+navsection: sdk
+navmenu: Python
+title: Examples
+...
+
+In these examples, the site prefix is @aaaaa@.
+
+h2. Initialize SDK
+
+<pre>
+import arvados
+api = arvados.api("v1")
+</pre>
+
+h2. create
+
+<pre>
+result = api.collection().create(body={"collection": {"name": "create example"}}).execute()
+</pre>
+
+h2. delete
+
+<pre>
+result = api.collections().delete(uuid="aaaaa-4zz18-ccccccccccccccc").execute()
+</pre>
+
+h2. get
+
+<pre>
+result = api.collections().get(uuid="aaaaa-4zz18-ccccccccccccccc").execute()
+</pre>
+
+h2. list
+
+<pre>
+result = api.collections().list(filters=[["uuid", "=", "aaaaa-bbbbb-ccccccccccccccc"]]).execute()
+</pre>
+
+h2. update
+
+<pre>
+result = api.collections().update(uuid="aaaaa-4zz18-ccccccccccccccc", body={"collection": {"name": "update example"}}).execute()
+</pre>
+
+h2. Get current user
+
+<pre>
+result = api.users().current().execute()
+</pre>
layout: default
navsection: sdk
navmenu: Python
-title: "Python SDK"
-
+title: "Installation"
...
The Python SDK provides access from Python to the Arvados API and Keep. It also includes a number of command line tools for using and administering Arvados and Keep, and some conveniences for use in Crunch scripts; see "Crunch utility libraries":crunch-utility-libraries.html for details.
--- /dev/null
+---
+layout: default
+navsection: sdk
+navmenu: Python
+title: Examples
+...
+
+h2. Initialize SDK
+
+Import the module and set up an API client user agent:
+
+<pre>
+require 'arvados'
+arv = Arvados.new(apiVersion: 'v1')
+</pre>
+
+The SDK retrieves the list of API methods from the server at run time. Therefore, the set of available methods is determined by the server version rather than the SDK version.
+
+h2. create
+
+Create an object:
+
+<pre>
+new_link = arv.link.create(link: {link_class: 'test', name: 'test'})
+</pre>
+
+h2. delete
+
+Delete an object:
+
+<pre>
+arv.link.delete(uuid: new_link[:uuid])
+</pre>
+
+h2. get
+
+Retrieve an object by ID:
+
+<pre>
+some_user = arv.user.get(uuid: current_user_uuid)
+</pre>
+
+h2. list
+
+Get a list of objects:
+
+<pre>
+repos = arv.repository.list
+first_repo = repos[:items][0]
+puts "UUID of first repo returned is #{first_repo[:uuid]}"</code>
+UUID of first repo returned is qr1hi-s0uqq-b1bnybpx3u5temz
+</pre>
+
+h2. update
+
+Update an object:
+
+<pre>
+updated_link = arv.link.update(uuid: new_link[:uuid],
+ link: {properties: {foo: 'bar'}})
+</pre>
+
+h2. Get current user
+
+Get the User object for the current user:
+
+<pre>
+current_user = arv.user.current
+</pre>
+
+Get the UUID of an object that was retrieved using the SDK:
+
+<pre>
+current_user_uuid = current_user[:uuid]
+</pre>
layout: default
navsection: sdk
navmenu: Ruby
-title: "Ruby SDK"
-
+title: "Installation"
...
The Ruby SDK provides a generic set of wrappers so you can make API calls easily.
arvados.v1.users.current.full_name = 'Your Name'
</pre>
</notextile>
-
-h3. Examples
-
-Import the module (we skipped this step above by using "ruby -r arvados"):
-
-<notextile>
-<pre><code class="userinput">require 'arvados'
-</code></pre>
-</notextile>
-
-Set up an API client user agent:
-
-<notextile>
-<pre><code class="userinput">arv = Arvados.new(apiVersion: 'v1')
-</code></pre>
-</notextile>
-
-Get the User object for the current user:
-
-<notextile>
-<pre><code class="userinput">current_user = arv.user.current
-</code></pre>
-</notextile>
-
-Get the UUID of an object that was retrieved using the SDK:
-
-<notextile>
-<pre><code class="userinput">current_user_uuid = current_user[:uuid]
-</code></pre>
-</notextile>
-
-Retrieve an object by ID:
-
-<notextile>
-<pre><code class="userinput">some_user = arv.user.get(uuid: current_user_uuid)
-</code></pre>
-</notextile>
-
-Create an object:
-
-<notextile>
-<pre><code class="userinput">new_link = arv.link.create(link: {link_class: 'test', name: 'test'})
-</code></pre>
-</notextile>
-
-Update an object:
-
-<notextile>
-<pre><code class="userinput">updated_link = arv.link.update(uuid: new_link[:uuid],
- link: {properties: {foo: 'bar'}})
-</code></pre>
-</notextile>
-
-Delete an object:
-
-<notextile>
-<pre><code class="userinput">arv.link.delete(uuid: new_link[:uuid])
-</code></pre>
-</notextile>
-
-Get a list of objects:
-
-<notextile>
-<pre><code class="userinput">repos = arv.repository.list
-first_repo = repos[:items][0]
-puts "UUID of first repo returned is #{first_repo[:uuid]}"</code>
-UUID of first repo returned is qr1hi-s0uqq-b1bnybpx3u5temz
-</pre>
-</notextile>
-
-The SDK retrieves the list of API methods from the server at run time. Therefore, the set of available methods is determined by the server version rather than the SDK version.
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: Arvados CWL Extensions
+...
+
+Arvados provides several extensions to CWL for workflow optimization, site-specific configuration, and to enable access the Arvados API.
+
+To use Arvados CWL extensions, add the following @$namespaces@ section at the top of your CWL file:
+
+<pre>
+$namespaces:
+ arv: "http://arvados.org/cwl#"
+</pre>
+
+Arvados extensions must go into the @hints@ section, for example:
+
+<pre>
+hints:
+ arv:RunInSingleContainer: {}
+ arv:RuntimeConstraints:
+ keep_cache: 123456
+ keep_output_dir: local_output_dir
+ arv:PartitionRequirement:
+ partition: dev_partition
+ arv:APIRequirement: {}
+</pre>
+
+h2. arv:RunInSingleContainer
+
+Indicates that a subworkflow should run in a single container and not be scheduled as separate steps.
+
+h2. arv:RuntimeConstraints
+
+Set Arvados-specific runtime hints.
+
+table(table table-bordered table-condensed).
+|_. Field |_. Type |_. Description |
+|keep_cache|int|Size of file data buffer for Keep mount in MiB. Default is 256 MiB. Increase this to reduce cache thrashing in situations such as accessing multiple large (64+ MiB) files at the same time, or performing random access on a large file.|
+|outputDirType|enum|Preferred backing store for output staging. If not specified, the system may choose which one to use. One of *local_output_dir* or *keep_output_dir*|
+
+*local_output_dir*: Use regular file system local to the compute node. There must be sufficient local scratch space to store entire output; specify this with @outdirMin@ of @ResourceRequirement@. Files are batch uploaded to Keep when the process completes. Most compatible, but upload step can be time consuming for very large files.
+
+*keep_output_dir*: Use writable Keep mount. Files are streamed to Keep as they are written. Does not consume local scratch space, but does consume RAM for output buffers (up to 192 MiB per file simultaneously open for writing.) Best suited to processes which produce sequential output of large files (non-sequential writes may produced fragmented file manifests). Supports regular files and directories, does not support special files such as symlinks, hard links, named pipes, named sockets, or device nodes.|
+
+h2. arv:PartitionRequirement
+
+Select preferred compute partitions on which to run jobs.
+
+table(table table-bordered table-condensed).
+|_. Field |_. Type |_. Description |
+|partition|string or array of strings||
+
+h2. arv:APIRequirement
+
+Indicates that process wants to access to the Arvados API. Will be granted limited network access and have @ARVADOS_API_HOST@ and @ARVADOS_API_TOKEN@ set in the environment.
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: "Using arvados-cwl-runner"
+...
+
+The following command line options are available for @arvados-cwl-runner@:
+
+table(table table-bordered table-condensed).
+|_. Option |_. Description |
+|==--basedir== BASEDIR| Base directory used to resolve relative references in the input, default to directory of input object file or current directory (if inputs piped/provided on command line).|
+|==--version==| Print version and exit|
+|==--verbose==| Default logging|
+|==--quiet==| Only print warnings and errors.|
+|==--debug==| Print even more logging|
+|==--tool-help==| Print command line help for tool|
+|==--enable-reuse==|Enable job reuse (default)|
+|==--disable-reuse==|Disable job reuse (always run new jobs).|
+|==--project-uuid UUID==| Project that will own the workflow jobs, if not provided, will go to home project.|
+|==--output-name OUTPUT_NAME==|Name to use for collection that stores the final output.|
+|==--output-tags OUTPUT_TAGS==|Tags for the final output collection separated by commas, e.g., =='--output-tags tag0,tag1,tag2'==.|
+|==--ignore-docker-for-reuse==|Ignore Docker image version when deciding whether to reuse past jobs.|
+|==--submit==| Submit workflow to run on Arvados.|
+|==--local==| Control workflow from local host (submits jobs to Arvados).|
+|==--create-template==| (Deprecated) synonym for ==--create-workflow.==|
+|==--create-workflow==| Create an Arvados workflow (if using the 'containers' API) or pipeline template (if using the 'jobs' API). See ==--api==.|
+|==--update-workflow== UUID|Update an existing Arvados workflow or pipeline template with the given UUID.|
+|==--wait==| After submitting workflow runner job, wait for completion.|
+|==--no-wait==| Submit workflow runner job and exit.|
+|==--api== WORK_API| Select work submission API, one of 'jobs' or 'containers'. Default is 'jobs' if that API is available, otherwise 'containers'.|
+|==--compute-checksum==| Compute checksum of contents while collecting outputs|
+|==--submit-runner-ram== SUBMIT_RUNNER_RAM|RAM (in MiB) required for the workflow runner job (default 1024)|
+|==--name== NAME| Name to use for workflow execution instance.|
+
+h3. Specify workflow and output names
+
+Use the @--name@ and @--output-name@ options to specify the name of the workflow and name of the output collection.
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --name "Example bwa run" --output-name "Example bwa output" bwa-mem.cwl bwa-mem-input.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Upload local files: "bwa-mem.cwl"
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Uploaded to qr1hi-4zz18-h7ljh5u76760ww2
+2016-06-30 14:56:40 arvados.cwl-runner[27002] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
+2016-06-30 14:56:41 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Running
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Complete
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Overall process status is success
+{
+ "aligned_sam": {
+ "path": "keep:54325254b226664960de07b3b9482349+154/HWI-ST1027_129_D0THKACXX.1_1.sam",
+ "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
+ "class": "File",
+ "size": 30738986
+ }
+}
+</code></pre>
+</notextile>
+
+h3. Submit a workflow with no waiting
+
+To submit a workflow and exit immediately, use the @--no-wait@ option. This will submit the workflow to Arvados, print out the UUID of the job that was submitted to standard output, and exit.
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --no-wait bwa-mem.cwl bwa-mem-input.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-06-30 15:07:52 arvados.arv-run[12480] INFO: Upload local files: "bwa-mem.cwl"
+2016-06-30 15:07:52 arvados.arv-run[12480] INFO: Uploaded to qr1hi-4zz18-eqnfwrow8aysa9q
+2016-06-30 15:07:52 arvados.cwl-runner[12480] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
+qr1hi-8i9sb-fm2n3b1w0l6bskg
+</code></pre>
+</notextile>
+
+h3. Control a workflow locally
+
+To run a workflow with local control, use @--local@. This means that the host where you run @arvados-cwl-runner@ will be responsible for submitting jobs, however, the jobs themselves will still run on the Arvados cluster. With @--local@, if you interrupt @arvados-cwl-runner@ or log out, the workflow will be terminated.
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --local bwa-mem.cwl bwa-mem-input.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-07-01 10:05:19 arvados.cwl-runner[16290] INFO: Pipeline instance qr1hi-d1hrv-92wcu6ldtio74r4
+2016-07-01 10:05:28 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Queued
+2016-07-01 10:05:29 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Running
+2016-07-01 10:05:45 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Complete
+2016-07-01 10:05:46 arvados.cwl-runner[16290] INFO: Overall process status is success
+{
+ "aligned_sam": {
+ "size": 30738986,
+ "path": "keep:15f56bad0aaa7364819bf14ca2a27c63+88/HWI-ST1027_129_D0THKACXX.1_1.sam",
+ "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
+ "class": "File"
+ }
+}
+</code></pre>
+</notextile>
---
layout: default
navsection: userguide
-title: Using Common Workflow Language
+title: "Running an Arvados workflow"
...
-The "Common Workflow Language (CWL)":http://commonwl.org is a multi-vendor open standard for describing analysis tools and workflows that are portable across a variety of platforms. CWL is the recommended way to develop and run workflows for Arvados. Arvados supports the "CWL v1.0":http://commonwl.org/v1.0 specification.
+{% include 'what_is_cwl' %}
{% include 'tutorial_expectations' %}
-h2. Setting up
+{% include 'notebox_begin' %}
-The @arvados-cwl-runner@ client is installed by default on Arvados shell nodes. However, if you do not have @arvados-cwl-runner@, you may install it using @pip@:
+By default, the @arvados-cwl-runner@ is installed on Arvados shell nodes. If you want to submit jobs from somewhere else, such as your workstation, you may install "arvados-cwl-runner.":#setup
-<notextile>
-<pre><code>~$ <span class="userinput">virtualenv ~/venv</span>
-~$ <span class="userinput">. ~/venv/bin/activate</span>
-~$ <span class="userinput">pip install arvados-cwl-runner</span>
-</code></pre>
-</notextile>
+{% include 'notebox_end' %}
-h3. Docker
+This tutorial will demonstrate how to submit a workflow at the command line using @arvados-cwl-runner@.
-Certain features of @arvados-cwl-runner@ require access to Docker. You can determine if you have access to Docker by running @docker version@:
+h2. Running arvados-cwl-runner
-<notextile>
-<pre><code>~$ <span class="userinput">docker version</span>
-Client:
- Version: 1.9.1
- API version: 1.21
- Go version: go1.4.2
- Git commit: a34a1d5
- Built: Fri Nov 20 12:59:02 UTC 2015
- OS/Arch: linux/amd64
+h3. Get the example files
-Server:
- Version: 1.9.1
- API version: 1.21
- Go version: go1.4.2
- Git commit: a34a1d5
- Built: Fri Nov 20 12:59:02 UTC 2015
- OS/Arch: linux/amd64
-</code></pre>
-</notextile>
-
-If this returns an error, contact the sysadmin of your cluster for assistance. Alternatively, if you have Docker installed on your local workstation, you may follow the instructions above to install @arvados-cwl-runner@.
-
-h3. Getting the example files
-
-The tutorial files are located in the documentation section of the Arvados source repository:
+The tutorial files are located in the "documentation section of the Arvados source repository:":https://github.com/curoverse/arvados/tree/master/doc/user/cwl/bwa-mem
<notextile>
<pre><code>~$ <span class="userinput">git clone https://github.com/curoverse/arvados</span>
<notextile>
<pre><code>~$ <span class="userinput">arv-copy --src qr1hi --dst settings 2463fa9efeb75e099685528b3b9071e0+438</span>
~$ <span class="userinput">arv-copy --src qr1hi --dst settings ae480c5099b81e17267b7445e35b4bc7+180</span>
+~$ <span class="userinput">arv-copy --src qr1hi --dst settings 655c6cd07550151b210961ed1d3852cf+57</span>
</code></pre>
</notextile>
"https://cloud.curoverse.com/collections/ae480c5099b81e17267b7445e35b4bc7+180":https://cloud.curoverse.com/collections/ae480c5099b81e17267b7445e35b4bc7+180
+"https://cloud.curoverse.com/collections/655c6cd07550151b210961ed1d3852cf+57":https://cloud.curoverse.com/collections/655c6cd07550151b210961ed1d3852cf+57
+
h2. Submitting a workflow to an Arvados cluster
-Use @arvados-cwl-runner@ to submit CWL workflows to Arvados. After submitting the job, it will wait for the workflow to complete and print out the final result to standard output. Note that once submitted, the workflow runs entirely on Arvados, so even if you interrupt @arvados-cwl-runner@ or log out, the workflow will continue to run.
+h3. Submit a workflow and wait for results
+
+Use @arvados-cwl-runner@ to submit CWL workflows to Arvados. After submitting the job, it will wait for the workflow to complete and print out the final result to standard output.
+
+*Note:* Once submitted, the workflow runs entirely on Arvados, so even if you log out, the workflow will continue to run. However, if you interrupt @arvados-cwl-runner@ with control-C it will cancel the workflow.
<notextile>
<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner bwa-mem.cwl bwa-mem-input.yml</span>
</code></pre>
</notextile>
-To submit a workflow and exit immediately, use the @--no-wait@ option. This will print out the uuid of the job that was submitted to standard output.
-
-<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --no-wait bwa-mem.cwl bwa-mem-input.yml</span>
-arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-06-30 15:07:52 arvados.arv-run[12480] INFO: Upload local files: "bwa-mem.cwl"
-2016-06-30 15:07:52 arvados.arv-run[12480] INFO: Uploaded to qr1hi-4zz18-eqnfwrow8aysa9q
-2016-06-30 15:07:52 arvados.cwl-runner[12480] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
-qr1hi-8i9sb-fm2n3b1w0l6bskg
-</code></pre>
-</notextile>
-
-To run a workflow with local control, use @--local@. This means that the host where you run @arvados-cwl-runner@ will be responsible for submitting jobs. With @--local@, if you interrupt @arvados-cwl-runner@ or log out, the workflow will be terminated.
-
-<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --local bwa-mem.cwl bwa-mem-input.yml</span>
-arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-07-01 10:05:19 arvados.cwl-runner[16290] INFO: Pipeline instance qr1hi-d1hrv-92wcu6ldtio74r4
-2016-07-01 10:05:28 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Queued
-2016-07-01 10:05:29 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Running
-2016-07-01 10:05:45 arvados.cwl-runner[16290] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-2nzzfbuf9zjrj4g) is Complete
-2016-07-01 10:05:46 arvados.cwl-runner[16290] INFO: Overall process status is success
-{
- "aligned_sam": {
- "size": 30738986,
- "path": "keep:15f56bad0aaa7364819bf14ca2a27c63+88/HWI-ST1027_129_D0THKACXX.1_1.sam",
- "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
- "class": "File"
- }
-}
-</code></pre>
-</notextile>
-
-h2. Work reuse
-
-Workflows submitted with @arvados-cwl-runner@ will take advantage of Arvados job reuse. If you submit a workflow which is identical to one that has run before, it will short cut the execution and return the result of the previous run. This also applies to individual workflow steps. For example, a two step workflow where the first step has run before will reuse results for first step and only execute the new second step. You can disable this behavior with @--disable-reuse@.
-
-h2. Referencing files
+h3. Referencing files
When running a workflow on an Arvados cluster, the input files must be stored in Keep. There are several ways this can happen.
If you reference a local file which is not in @arv-mount@, then @arvados-cwl-runner@ will upload the file to Keep and use the Keep URI reference from the upload.
-h2. Registering a workflow with Workbench
-
-Use @--create-template@ to register a CWL workflow with Arvados Workbench. This enables you to run workflows by clicking on the <span class="btn btn-sm btn-primary"><i class="fa fa-fw fa-gear"></i> Run a pipeline...</span> on the Workbench Dashboard.
-
-<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --create-template bwa-mem.cwl</span>
-arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-07-01 12:21:01 arvados.arv-run[15796] INFO: Upload local files: "bwa-mem.cwl"
-2016-07-01 12:21:01 arvados.arv-run[15796] INFO: Uploaded to qr1hi-4zz18-7e0hedrmkuyoei3
-2016-07-01 12:21:01 arvados.cwl-runner[15796] INFO: Created template qr1hi-p5p6p-rjleou1dwr167v5
-qr1hi-p5p6p-rjleou1dwr167v5
-</code></pre>
-</notextile>
-
-You can provide a partial input file to set default values for the workflow input parameters:
-
-<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --create-template bwa-mem.cwl bwa-mem-template.yml</span>
-arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-07-01 14:09:50 arvados.arv-run[3730] INFO: Upload local files: "bwa-mem.cwl"
-2016-07-01 14:09:50 arvados.arv-run[3730] INFO: Uploaded to qr1hi-4zz18-0f91qkovk4ml18o
-2016-07-01 14:09:50 arvados.cwl-runner[3730] INFO: Created template qr1hi-p5p6p-0deqe6nuuyqns2i
-qr1hi-p5p6p-0deqe6nuuyqns2i
-</code></pre>
-</notextile>
-
-h2. Making workflows directly executable
-
-You can make a workflow file directly executable (@cwl-runner@ should be an alias to @arvados-cwl-runner@) by adding the following line to the top of the file:
+You can also execute CWL files directly from Keep:
<notextile>
-<pre><code>#!/usr/bin/env cwl-runner
-</code></pre>
-</notextile>
-
-<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">./bwa-mem.cwl bwa-mem-input.yml</span>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner keep:655c6cd07550151b210961ed1d3852cf+57/bwa-mem.cwl bwa-mem-input.yml</span>
arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Upload local files: "bwa-mem.cwl"
2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Uploaded to qr1hi-4zz18-h7ljh5u76760ww2
2016-06-30 14:56:40 arvados.cwl-runner[27002] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
2016-06-30 14:56:41 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Running
</code></pre>
</notextile>
-You can even make an input file directly executable the same way with the following two lines at the top:
+h3. Work reuse
-<notextile>
-<pre><code>#!/usr/bin/env cwl-runner
-cwl:tool: <span class="userinput">bwa-mem.cwl</span>
-</code></pre>
-</notextile>
+Workflows submitted with @arvados-cwl-runner@ will take advantage of Arvados job reuse. If you submit a workflow which is identical to one that has run before, it will short cut the execution and return the result of the previous run. This also applies to individual workflow steps. For example, a two step workflow where the first step has run before will reuse results for first step and only execute the new second step. You can disable this behavior with @--disable-reuse@.
+
+h3. Command line options
+
+See "Using arvados-cwl-runner":{{site.baseurl}}/user/cwl/cwl-run-options.html
+
+h2(#setup). Setting up arvados-cwl-runner
+
+By default, the @arvados-cwl-runner@ is installed on Arvados shell nodes. If you want to submit jobs from somewhere else, such as your workstation, you may install @arvados-cwl-runner@ using @pip@:
<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">./bwa-mem-input.yml</span>
-arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
-2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Upload local files: "bwa-mem.cwl"
-2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Uploaded to qr1hi-4zz18-h7ljh5u76760ww2
-2016-06-30 14:56:40 arvados.cwl-runner[27002] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
-2016-06-30 14:56:41 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Running
-2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Complete
-2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Overall process status is success
-{
- "aligned_sam": {
- "path": "keep:54325254b226664960de07b3b9482349+154/HWI-ST1027_129_D0THKACXX.1_1.sam",
- "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
- "class": "File",
- "size": 30738986
- }
-}
+<pre><code>~$ <span class="userinput">virtualenv ~/venv</span>
+~$ <span class="userinput">. ~/venv/bin/activate</span>
+~$ <span class="userinput">pip install -U setuptools</span>
+~$ <span class="userinput">pip install arvados-cwl-runner</span>
</code></pre>
</notextile>
-h2. Developing workflows
+h3. Check Docker access
-For an introduction and and detailed documentation about writing CWL, see the "User Guide":http://commonwl.org/v1.0/UserGuide.html and the "Specification":http://commonwl.org/v1.0 .
+In order to pull and upload Docker images, @arvados-cwl-runner@ requires access to Docker. You do not need Docker if the Docker images you intend to use are already available in Aravdos.
-To run on Arvados, a workflow should provide a @DockerRequirement@ in the @hints@ section.
-
-When developing a workflow, it is often helpful to run it on the local host to avoid the overhead of submitting to the cluster. To execute a workflow only on the local host (without submitting jobs to an Arvados cluster) you can use the @cwltool@ command. Note that you must also have the input data accessible on the local host. You can use @arv-get@ to fetch the data from Keep.
+You can determine if you have access to Docker by running @docker version@:
<notextile>
-<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arv-get 2463fa9efeb75e099685528b3b9071e0+438/ .</span>
-156 MiB / 156 MiB 100.0%
-~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arv-get ae480c5099b81e17267b7445e35b4bc7+180/ .</span>
-23 MiB / 23 MiB 100.0%
-~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">cwltool bwa-mem-input.yml bwa-mem-input-local.yml</span>
-cwltool 1.0.20160629140624
-[job bwa-mem.cwl] /home/example/arvados/doc/user/cwl/bwa-mem$ docker \
- run \
- -i \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.ann:/var/lib/cwl/job979368791_bwa-mem/19.fasta.ann:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq:/var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.sa:/var/lib/cwl/job979368791_bwa-mem/19.fasta.sa:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.amb:/var/lib/cwl/job979368791_bwa-mem/19.fasta.amb:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.pac:/var/lib/cwl/job979368791_bwa-mem/19.fasta.pac:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq:/var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.bwt:/var/lib/cwl/job979368791_bwa-mem/19.fasta.bwt:ro \
- --volume=/home/example/arvados/doc/user/cwl/bwa-mem:/var/spool/cwl:rw \
- --volume=/tmp/tmpgzyou9:/tmp:rw \
- --workdir=/var/spool/cwl \
- --read-only=true \
- --log-driver=none \
- --user=1001 \
- --rm \
- --env=TMPDIR=/tmp \
- --env=HOME=/var/spool/cwl \
- biodckr/bwa \
- bwa \
- mem \
- -t \
- 1 \
- -R \
- '@RG ID:arvados_tutorial PL:illumina SM:HWI-ST1027_129' \
- /var/lib/cwl/job979368791_bwa-mem/19.fasta \
- /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq \
- /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq > /home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.sam
-[M::bwa_idx_load_from_disk] read 0 ALT contigs
-[M::process] read 100000 sequences (10000000 bp)...
-[M::mem_pestat] # candidate unique pairs for (FF, FR, RF, RR): (0, 4745, 1, 0)
-[M::mem_pestat] skip orientation FF as there are not enough pairs
-[M::mem_pestat] analyzing insert size distribution for orientation FR...
-[M::mem_pestat] (25, 50, 75) percentile: (154, 181, 214)
-[M::mem_pestat] low and high boundaries for computing mean and std.dev: (34, 334)
-[M::mem_pestat] mean and std.dev: (185.63, 44.88)
-[M::mem_pestat] low and high boundaries for proper pairs: (1, 394)
-[M::mem_pestat] skip orientation RF as there are not enough pairs
-[M::mem_pestat] skip orientation RR as there are not enough pairs
-[M::mem_process_seqs] Processed 100000 reads in 9.848 CPU sec, 9.864 real sec
-[main] Version: 0.7.12-r1039
-[main] CMD: bwa mem -t 1 -R @RG ID:arvados_tutorial PL:illumina SM:HWI-ST1027_129 /var/lib/cwl/job979368791_bwa-mem/19.fasta /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq
-[main] Real time: 10.061 sec; CPU: 10.032 sec
-Final process status is success
-{
- "aligned_sam": {
- "size": 30738959,
- "path": "/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.sam",
- "checksum": "sha1$0c668cca45fef02397bb5302880526d300ee4dac",
- "class": "File"
- }
-}
+<pre><code>~$ <span class="userinput">docker version</span>
+Client:
+ Version: 1.9.1
+ API version: 1.21
+ Go version: go1.4.2
+ Git commit: a34a1d5
+ Built: Fri Nov 20 12:59:02 UTC 2015
+ OS/Arch: linux/amd64
+
+Server:
+ Version: 1.9.1
+ API version: 1.21
+ Go version: go1.4.2
+ Git commit: a34a1d5
+ Built: Fri Nov 20 12:59:02 UTC 2015
+ OS/Arch: linux/amd64
</code></pre>
</notextile>
-If you get the error @JavascriptException: Long-running script killed after 20 seconds.@ this may be due to the Dockerized Node.js engine taking too long to start. You may address this by installing Node.js locally (run @apt-get install nodejs@ on Debian or Ubuntu) or by specifying a longer timeout with the @--eval-timeout@ option. For example, run the workflow with @cwltool --eval-timeout=40@ for a 40-second timeout.
+If this returns an error, contact the sysadmin of your cluster for assistance.
title: Best Practices for writing CWL
...
+* To run on Arvados, a workflow should provide a @DockerRequirement@ in the @hints@ section.
+
* Build a reusable library of components. Share tool wrappers and subworkflows between projects. Make use of and contribute to "community maintained workflows and tools":https://github.com/common-workflow-language/workflows and tool registries such as "Dockstore":http://dockstore.org .
* When combining a parameter value with a string, such as adding a filename extension, write @$(inputs.file.basename).ext@ instead of @$(inputs.file.basename + 'ext')@. The first form is evaluated as a simple text substitution, the second form (using the @+@ operator) is evaluated as an arbitrary Javascript expression and requires that you declare @InlineJavascriptRequirement@.
title: "Scripts provided by Arvados"
...
+{% include 'pipeline_deprecation_notice' %}
+
Several crunch scripts are included with Arvados in the "/crunch_scripts directory":https://dev.arvados.org/projects/arvados/repository/revisions/master/show/crunch_scripts. They are intended to provide examples and starting points for writing your own scripts.
h4. bwa-aln
You may be asked to log in using a Google account. Arvados uses only your name and email address from Google services for identification, and will never access any personal information. If you are accessing Arvados for the first time, the Workbench may indicate your account status is *New / inactive*. If this is the case, contact the administrator of the Arvados instance to request activation of your account.
-Once your account is active, logging in to the Workbench will present you with the Dashboard. This gives a summary of your projects and recent activity in the Arvados instance. "You are now ready to run your first pipeline.":{{ site.baseurl }}/user/tutorials/tutorial-pipeline-workbench.html
+Once your account is active, logging in to the Workbench will present you with the Dashboard. This gives a summary of your projects and recent activity in the Arvados instance. "You are now ready to run your first pipeline.":{{ site.baseurl }}/user/tutorials/tutorial-workflow-workbench.html
-!{{ site.baseurl }}/images/workbench-dashboard.png!
+!{display: block;margin-left: 25px;margin-right: auto;border:1px solid lightgray;}{{ site.baseurl }}/images/workbench-dashboard.png!
title: "Pipeline template reference"
...
-Pipeline template options are described on the "pipeline template schema page.":{{site.baseurl}}/api/schema/PipelineTemplate.html
+{% include 'pipeline_deprecation_notice' %}
+
+Pipeline template options are described on the "pipeline template schema page.":{{site.baseurl}}/api/methods/pipeline_templates.html
title: "Using arv-copy"
...
+{% include 'crunch1only_begin' %}
+On those sites, the "copy a pipeline template" feature described below is not available. However, "copy a workflow" feature is not yet implemented.
+{% include 'crunch1only_end' %}
This tutorial describes how to copy Arvados objects from one cluster to another by using @arv-copy@.
<pre><code>~$ <span class="userinput">arv-copy --src qr1hi --dst dst_cluster --dst-git-repo $USER/tutorial --no-recursive qr1hi-p5p6p-9pkaxt6qjnkxhhu</span>
</code></pre>
</notextile>
+
+h3. How to copy a workflow
+
+We will use the uuid @zzzzz-7fd4e-sampleworkflow1@ as an example workflow.
+
+<notextile>
+<pre><code>~$ <span class="userinput">arv-copy --src zzzzz --dst dst_cluster --dst-git-repo $USER/tutorial zzzzz-7fd4e-sampleworkflow1</span>
+zzzzz-4zz18-jidprdejysravcr: 1143M / 1143M 100.0%
+2017-01-04 04:11:58 arvados.arv-copy[5906] INFO:
+2017-01-04 04:11:58 arvados.arv-copy[5906] INFO: Success: created copy with uuid dst_cluster-7fd4e-ojtgpne594ubkt7
+</code></pre>
+</notextile>
+
+The name, description, and workflow definition from the original workflow will be used for the destination copy. In addition, any *locations* and *docker images* found in the src workflow definition will also be copied to the destination recursively.
+
+If you would like to copy the object without dependencies, you can use the @--no-recursive@ flag.
+
+For example, we can copy the same object non-recursively using the following:
+
+<notextile>
+<pre><code>~$ <span class="userinput">arv-copy --src zzzzz --dst dst_cluster --dst-git-repo $USER/tutorial --no-recursive zzzzz-7fd4e-sampleworkflow1</span>
+</code></pre>
+</notextile>
</code></pre>
</notextile>
-You are now able to specify the runtime environment for your program using the @docker_image@ field of the @runtime_constaints@ section of your pipeline components:
+You are now able to specify the runtime environment for your program using @DockerRequirement@ in your workflow:
-<notextile>
-{% code 'example_docker' as javascript %}
-</notextile>
-
-* The @docker_image@ field can be one of: the Docker repository name (as shown above), the Docker image hash, or the Arvados collection portable data hash.
+<pre>
+hints:
+ DockerRequirement:
+ dockerPull: arvados/jobs-with-r
+</pre>
h2. Share Docker images
title: "Using arv-run"
...
+{% include 'crunch1only_begin' %}
+On those sites, the features described here are not yet implemented.
+{% include 'crunch1only_end' %}
+
The @arv-run@ command enables you create Arvados pipelines at the command line that fan out to multiple concurrent tasks across Arvados compute nodes.
{% include 'tutorial_expectations' %}
title: "run-command reference"
...
+{% include 'pipeline_deprecation_notice' %}
+
The @run-command@ crunch script enables you run command line programs.
{% include 'tutorial_expectations_workstation' %}
title: "Running an Arvados pipeline"
...
-This tutorial demonstrates how to use the command line to run the same pipeline as described in "running a pipeline using Workbench.":{{site.baseurl}}/user/tutorials/tutorial-pipeline-workbench.html
+{% include 'crunch1only_begin' %}
+If the Jobs API is not available, use the "Common Workflow Language":{{site.baseurl}}/user/cwl/cwl-runner.html instead.
+{% include 'crunch1only_end' %}
+
+This tutorial demonstrates how to use the command line to run the same pipeline as described in "running a pipeline using Workbench.":{{site.baseurl}}/user/tutorials/tutorial-workflow-workbench.html
{% include 'tutorial_expectations' %}
{% include 'tutorial_cluster_name' %}
* @"name"@ is a human-readable name for the pipeline.
* @"components"@ is a set of scripts or commands that make up the pipeline. Each component is given an identifier (@"bwa-mem"@ and @"SortSam"@) in this example).
-** Each entry in components @"components"@ is an Arvados job submission. For more information about individual jobs, see the "job object reference":{{site.baseurl}}/api/schema/Job.html and "job create method.":{{site.baseurl}}/api/methods/jobs.html#create
+** Each entry in components @"components"@ is an Arvados job submission. For more information about individual jobs, see the "job resource reference.":{{site.baseurl}}/api/methods/jobs.html
* @"repository"@, @"script_version"@, and @"script"@ indicate that we intend to use the external @"run-command"@ tool wrapper that is part of the Arvados. These parameters are described in more detail in "Writing a script":tutorial-firstscript.html.
* @"runtime_constraints"@ describes runtime resource requirements for the component.
** @"docker_image"@ specifies the "Docker":https://www.docker.com/ runtime environment in which to run the job. The Docker image @"bcosc/arv-base-java"@ supplied here has the Java runtime environment, bwa, and samtools installed.
h2. Running your pipeline
-Your new pipeline template should appear at the top of the Workbench "pipeline templates":{{site.arvados_workbench_host}}/pipeline_templates page. You can run your pipeline "using Workbench":tutorial-pipeline-workbench.html or the "command line.":{{site.baseurl}}/user/topics/running-pipeline-command-line.html
+Your new pipeline template should appear at the top of the Workbench "pipeline templates":{{site.arvados_workbench_host}}/pipeline_templates page. You can run your pipeline "using Workbench":tutorial-workflow-workbench.html or the "command line.":{{site.baseurl}}/user/topics/running-pipeline-command-line.html
Test data is available in the "Arvados Tutorial":{{site.arvados_workbench_host}}/projects/qr1hi-j7d0g-u7zg1qdaowykd8d project:
* Choose <i class="fa fa-fw fa-archive"></i> "Tutorial chromosome 19 reference (2463fa9efeb75e099685528b3b9071e0+438)":{{site.arvados_workbench_host}}/collections/2463fa9efeb75e099685528b3b9071e0+438 for the "reference_collection" parameter
* Choose <i class="fa fa-fw fa-archive"></i> "Tutorial sample exome (3229739b505d2b878b62aed09895a55a+142)":{{site.arvados_workbench_host}}/collections/3229739b505d2b878b62aed09895a55a+142 for the "sample" parameter
-For more information and examples for writing pipelines, see the "pipeline template reference":{{site.baseurl}}/api/schema/PipelineTemplate.html
+For more information and examples for writing pipelines, see the "pipeline template reference":{{site.baseurl}}/api/methods/pipeline_templates.html
h2. Re-using your pipeline run
+++ /dev/null
----
-layout: default
-navsection: userguide
-title: "Running a pipeline using Workbench"
-...
-
-A "pipeline" (sometimes called a "workflow" in other systems) is a sequence of steps that apply various programs or tools to transform input data to output data. Pipelines are the principal means of performing computation with Arvados. This tutorial demonstrates how to run a single-stage pipeline to take a small data set of paired-end reads from a sample "exome":https://en.wikipedia.org/wiki/Exome in "FASTQ":https://en.wikipedia.org/wiki/FASTQ_format format and align them to "Chromosome 19":https://en.wikipedia.org/wiki/Chromosome_19_%28human%29 using the "bwa mem":http://bio-bwa.sourceforge.net/ tool, producing a "Sequence Alignment/Map (SAM)":https://samtools.github.io/ file. This tutorial will introduce the following Arvados features:
-
-<div>
-* How to create a new pipeline from an existing template.
-* How to browse and select input data for the pipeline and submit the pipeline to run on the Arvados cluster.
-* How to access your pipeline results.
-</div>
-
-notextile. <div class="spaced-out">
-
-h3. Steps
-
-# Start from the *Workbench Dashboard*. You can access the Dashboard by clicking on *<i class="fa fa-lg fa-fw fa-dashboard"></i> Dashboard* in the upper left corner of any Workbench page.
-# Click on the <span class="btn btn-sm btn-primary"><i class="fa fa-fw fa-gear"></i> Run a pipeline...</span> button. This will open a dialog box titled *Choose a pipeline to run*.
-# In the search box, type in *Tutorial align using bwa mem*.
-# Select *<i class="fa fa-fw fa-gear"></i> Tutorial align using bwa mem* and click the <span class="btn btn-sm btn-primary" >Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i></span> button. This will create a new pipeline in your *Home* project and will open it. You can now supply the inputs for the pipeline.
-# The first input parameter to the pipeline is *"reference_collection" parameter for run-command script in bwa-mem component*. Click the <span class="btn btn-sm btn-primary">Choose</span> button beneath that header. This will open a dialog box titled *Choose a dataset for "reference_collection" parameter for run-command script in bwa-mem component*.
-# Open the *Home <span class="caret"></span>* menu and select *All Projects*. Search for and select *<i class="fa fa-fw fa-archive"></i> Tutorial chromosome 19 reference* and click the <span class="btn btn-sm btn-primary" >OK</span> button.
-# Repeat the previous two steps to set the *"sample" parameter for run-command script in bwa-mem component* parameter to *<i class="fa fa-fw fa-archive"></i> Tutorial sample exome*.
-# Click on the <span class="btn btn-sm btn-primary" >Run <i class="fa fa-fw fa-play"></i></span> button. The page updates to show you that the pipeline has been submitted to run on the Arvados cluster.
-# After the pipeline starts running, you can track the progress by watching log messages from jobs. This page refreshes automatically. You will see a <span class="label label-success">complete</span> label when the pipeline completes successfully.
-# Click on the *Output* link to see the results of the job. This will load a new page listing the output files from this pipeline. You'll see the output SAM file from the alignment tool under the *Files* tab.
-# Click on the <span class="btn btn-sm btn-info"><i class="fa fa-download"></i></span> download button to the right of the SAM file to download your results.
-
-notextile. </div>
* @"repository"@ is the name of a git repository to search for the script version. You can access a list of available git repositories on the Arvados Workbench in the *Repositories* page using the <span class="fa fa-lg fa-user"></span> <span class="caret"></span> top navigation menu icon.
* @"script_version"@ specifies the version of the script that you wish to run. This can be in the form of an explicit Git revision hash, a tag, or a branch (in which case it will use the HEAD of the specified branch). Arvados logs the script version that was used in the run, enabling you to go back and re-run any past job with the guarantee that the exact same code will be used as was used in the previous run.
* @"script"@ specifies the filename of the script to run. Crunch expects to find this in the @crunch_scripts/@ subdirectory of the Git repository.
-* @"runtime_constraints"@ describes the runtime environment required to run the job. These are described in the "job record schema":{{site.baseurl}}/api/schema/Job.html
+* @"runtime_constraints"@ describes the runtime environment required to run the job. These are described in the "job record schema":{{site.baseurl}}/api/methods/jobs.html
h2. Running your pipeline
-Your new pipeline template should appear at the top of the Workbench "pipeline templates":{{site.arvados_workbench_host}}/pipeline_templates page. You can run your pipeline "using Workbench":tutorial-pipeline-workbench.html or the "command line.":{{site.baseurl}}/user/topics/running-pipeline-command-line.html
+Your new pipeline template should appear at the top of the Workbench "pipeline templates":{{site.arvados_workbench_host}}/pipeline_templates page. You can run your pipeline "using Workbench":tutorial-workflow-workbench.html or the "command line.":{{site.baseurl}}/user/topics/running-pipeline-command-line.html
-For more information and examples for writing pipelines, see the "pipeline template reference":{{site.baseurl}}/api/schema/PipelineTemplate.html
+For more information and examples for writing pipelines, see the "pipeline template reference":{{site.baseurl}}/api/methods/pipeline_templates.html
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: "Running a workflow using Workbench"
+...
+
+A "workflow" (sometimes called a "pipeline" in other systems) is a sequence of steps that apply various programs or tools to transform input data to output data. Workflows are the principal means of performing computation with Arvados. This tutorial demonstrates how to run a single-stage workflow to take a small data set of paired-end reads from a sample "exome":https://en.wikipedia.org/wiki/Exome in "FASTQ":https://en.wikipedia.org/wiki/FASTQ_format format and align them to "Chromosome 19":https://en.wikipedia.org/wiki/Chromosome_19_%28human%29 using the "bwa mem":http://bio-bwa.sourceforge.net/ tool, producing a "Sequence Alignment/Map (SAM)":https://samtools.github.io/ file. This tutorial will introduce the following Arvados features:
+
+<div>
+* How to create a new process from an existing workflow.
+* How to browse and select input data for the workflow and submit the process to run on the Arvados cluster.
+* How to access your process results.
+</div>
+
+h3. Steps
+
+# Start from the *Workbench Dashboard*. You can access the Dashboard by clicking on *<i class="fa fa-lg fa-fw fa-dashboard"></i> Dashboard* in the upper left corner of any Workbench page.
+# Click on the <span class="btn btn-sm btn-primary"><i class="fa fa-fw fa-gear"></i> Run a process...</span> button. This will open a dialog box titled *Choose a pipeline or workflow to run*.
+# In the search box, type in *Tutorial bwa mem cwl*.
+# Select *<i class="fa fa-fw fa-gear"></i> Tutorial bwa mem cwl* and click the <span class="btn btn-sm btn-primary" >Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i></span> button. This will create a new process in your *Home* project and will open it. You can now supply the inputs for the process. Please note that all required inputs are populated with default values and you can change them if you prefer.
+# For example, let's see how to change *"reference" parameter* for this workflow. Click the <span class="btn btn-sm btn-primary">Choose</span> button beneath the *"reference" parameter* header. This will open a dialog box titled *Choose a dataset for "reference" parameter for cwl-runner in bwa-mem.cwl component*.
+# Open the *Home <span class="caret"></span>* menu and select *All Projects*. Search for and select *<i class="fa fa-fw fa-archive"></i> Tutorial chromosome 19 reference*. You will then see a list of files. Select *<i class="fa fa-fw fa-file"></i> 19-fasta.bwt* and click the <span class="btn btn-sm btn-primary" >OK</span> button.
+# Repeat the previous two steps to set the *"read_p1" parameter for cwl-runner script in bwa-mem.cwl component* and *"read_p2" parameter for cwl-runner script in bwa-mem.cwl component* parameters.
+# Click on the <span class="btn btn-sm btn-primary" >Run <i class="fa fa-fw fa-play"></i></span> button. The page updates to show you that the process has been submitted to run on the Arvados cluster.
+# After the process starts running, you can track the progress by watching log messages from the component(s). This page refreshes automatically. You will see a <span class="label label-success">complete</span> label when the process completes successfully.
+# Click on the *Output* link to see the results of the process. This will load a new page listing the output files from this process. You'll see the output SAM file from the alignment tool under the *Files* tab.
+# Click on the <span class="btn btn-sm btn-info"><i class="fa fa-download"></i></span> download button to the right of the SAM file to download your results.
--- /dev/null
+---
+layout: default
+navsection: userguide
+title: "Writing a CWL workflow"
+...
+
+{% include 'what_is_cwl' %}
+
+{% include 'tutorial_expectations' %}
+
+h2. Developing workflows
+
+For an introduction and and detailed documentation about writing CWL, see the "CWL User Guide":http://commonwl.org/v1.0/UserGuide.html and the "CWL Specification":http://commonwl.org/v1.0 .
+
+See "Best Practices for writing CWL":{{site.baseurl}}/user/cwl/cwl-style.html and "Arvados CWL Extensions":{{site.baseurl}}/user/cwl/cwl-extensions.html for additional information about using CWL on Arvados.
+
+h2. Registering a workflow to use in Workbench
+
+Use @--create-workflow@ to register a CWL workflow with Arvados. This enables you to share workflows with other Arvados users, and run them by clicking the <span class="btn btn-sm btn-primary"><i class="fa fa-fw fa-gear"></i> Run a process...</span> button on the Workbench Dashboard and on the command line by UUID.
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --create-workflow bwa-mem.cwl</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-07-01 12:21:01 arvados.arv-run[15796] INFO: Upload local files: "bwa-mem.cwl"
+2016-07-01 12:21:01 arvados.arv-run[15796] INFO: Uploaded to qr1hi-4zz18-7e0hedrmkuyoei3
+2016-07-01 12:21:01 arvados.cwl-runner[15796] INFO: Created template qr1hi-p5p6p-rjleou1dwr167v5
+qr1hi-p5p6p-rjleou1dwr167v5
+</code></pre>
+</notextile>
+
+You can provide a partial input file to set default values for the workflow input parameters. You can also use the @--name@ option to set the name of the workflow:
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner --name "My workflow with defaults" --create-workflow bwa-mem.cwl bwa-mem-template.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-07-01 14:09:50 arvados.arv-run[3730] INFO: Upload local files: "bwa-mem.cwl"
+2016-07-01 14:09:50 arvados.arv-run[3730] INFO: Uploaded to qr1hi-4zz18-0f91qkovk4ml18o
+2016-07-01 14:09:50 arvados.cwl-runner[3730] INFO: Created template qr1hi-p5p6p-0deqe6nuuyqns2i
+qr1hi-p5p6p-zuniv58hn8d0qd8
+</code></pre>
+</notextile>
+
+h3. Running registered workflows at the command line
+
+You can run a registered workflow at the command line by its UUID:
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arvados-cwl-runner qr1hi-p5p6p-zuniv58hn8d0qd8 --help</span>
+/home/peter/work/scripts/venv/bin/arvados-cwl-runner 0d62edcb9d25bf4dcdb20d8872ea7b438e12fc59 1.0.20161209192028, arvados-python-client 0.1.20161212125425, cwltool 1.0.20161207161158
+Resolved 'qr1hi-p5p6p-zuniv58hn8d0qd8' to 'keep:655c6cd07550151b210961ed1d3852cf+57/bwa-mem.cwl'
+usage: qr1hi-p5p6p-zuniv58hn8d0qd8 [-h] [--PL PL] --group_id GROUP_ID
+ --read_p1 READ_P1 [--read_p2 READ_P2]
+ [--reference REFERENCE] --sample_id
+ SAMPLE_ID
+ [job_order]
+
+positional arguments:
+ job_order Job input json file
+
+optional arguments:
+ -h, --help show this help message and exit
+ --PL PL
+ --group_id GROUP_ID
+ --read_p1 READ_P1 The reads, in fastq format.
+ --read_p2 READ_P2 For mate paired reads, the second file (optional).
+ --reference REFERENCE
+ The index files produced by `bwa index`
+ --sample_id SAMPLE_ID
+</code></pre>
+</notextile>
+
+h2. Using cwltool
+
+When developing a workflow, it is often helpful to run it on the local host to avoid the overhead of submitting to the cluster. To execute a workflow only on the local host (without submitting jobs to an Arvados cluster) you can use the @cwltool@ command. Note that when using @cwltool@ you must have the input data accessible on the local file system using either @arv-mount@ or @arv-get@ to fetch the data from Keep.
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arv-get 2463fa9efeb75e099685528b3b9071e0+438/ .</span>
+156 MiB / 156 MiB 100.0%
+~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">arv-get ae480c5099b81e17267b7445e35b4bc7+180/ .</span>
+23 MiB / 23 MiB 100.0%
+~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">cwltool bwa-mem-input.yml bwa-mem-input-local.yml</span>
+cwltool 1.0.20160629140624
+[job bwa-mem.cwl] /home/example/arvados/doc/user/cwl/bwa-mem$ docker \
+ run \
+ -i \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.ann:/var/lib/cwl/job979368791_bwa-mem/19.fasta.ann:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq:/var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.sa:/var/lib/cwl/job979368791_bwa-mem/19.fasta.sa:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.amb:/var/lib/cwl/job979368791_bwa-mem/19.fasta.amb:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.pac:/var/lib/cwl/job979368791_bwa-mem/19.fasta.pac:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq:/var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem/19.fasta.bwt:/var/lib/cwl/job979368791_bwa-mem/19.fasta.bwt:ro \
+ --volume=/home/example/arvados/doc/user/cwl/bwa-mem:/var/spool/cwl:rw \
+ --volume=/tmp/tmpgzyou9:/tmp:rw \
+ --workdir=/var/spool/cwl \
+ --read-only=true \
+ --log-driver=none \
+ --user=1001 \
+ --rm \
+ --env=TMPDIR=/tmp \
+ --env=HOME=/var/spool/cwl \
+ biodckr/bwa \
+ bwa \
+ mem \
+ -t \
+ 1 \
+ -R \
+ '@RG ID:arvados_tutorial PL:illumina SM:HWI-ST1027_129' \
+ /var/lib/cwl/job979368791_bwa-mem/19.fasta \
+ /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq \
+ /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq > /home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.sam
+[M::bwa_idx_load_from_disk] read 0 ALT contigs
+[M::process] read 100000 sequences (10000000 bp)...
+[M::mem_pestat] # candidate unique pairs for (FF, FR, RF, RR): (0, 4745, 1, 0)
+[M::mem_pestat] skip orientation FF as there are not enough pairs
+[M::mem_pestat] analyzing insert size distribution for orientation FR...
+[M::mem_pestat] (25, 50, 75) percentile: (154, 181, 214)
+[M::mem_pestat] low and high boundaries for computing mean and std.dev: (34, 334)
+[M::mem_pestat] mean and std.dev: (185.63, 44.88)
+[M::mem_pestat] low and high boundaries for proper pairs: (1, 394)
+[M::mem_pestat] skip orientation RF as there are not enough pairs
+[M::mem_pestat] skip orientation RR as there are not enough pairs
+[M::mem_process_seqs] Processed 100000 reads in 9.848 CPU sec, 9.864 real sec
+[main] Version: 0.7.12-r1039
+[main] CMD: bwa mem -t 1 -R @RG ID:arvados_tutorial PL:illumina SM:HWI-ST1027_129 /var/lib/cwl/job979368791_bwa-mem/19.fasta /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.fastq /var/lib/cwl/job979368791_bwa-mem/HWI-ST1027_129_D0THKACXX.1_2.fastq
+[main] Real time: 10.061 sec; CPU: 10.032 sec
+Final process status is success
+{
+ "aligned_sam": {
+ "size": 30738959,
+ "path": "/home/example/arvados/doc/user/cwl/bwa-mem/HWI-ST1027_129_D0THKACXX.1_1.sam",
+ "checksum": "sha1$0c668cca45fef02397bb5302880526d300ee4dac",
+ "class": "File"
+ }
+}
+</code></pre>
+</notextile>
+
+If you get the error @JavascriptException: Long-running script killed after 20 seconds.@ this may be due to the Dockerized Node.js engine taking too long to start. You may address this by installing Node.js locally (run @apt-get install nodejs@ on Debian or Ubuntu) or by specifying a longer timeout with the @--eval-timeout@ option. For example, run the workflow with @cwltool --eval-timeout=40@ for a 40-second timeout.
+
+h2. Making workflows directly executable
+
+You can make a workflow file directly executable (@cwl-runner@ should be an alias to @arvados-cwl-runner@) by adding the following line to the top of the file:
+
+<notextile>
+<pre><code>#!/usr/bin/env cwl-runner
+</code></pre>
+</notextile>
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">./bwa-mem.cwl bwa-mem-input.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Upload local files: "bwa-mem.cwl"
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Uploaded to qr1hi-4zz18-h7ljh5u76760ww2
+2016-06-30 14:56:40 arvados.cwl-runner[27002] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
+2016-06-30 14:56:41 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Running
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Complete
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Overall process status is success
+{
+ "aligned_sam": {
+ "path": "keep:54325254b226664960de07b3b9482349+154/HWI-ST1027_129_D0THKACXX.1_1.sam",
+ "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
+ "class": "File",
+ "size": 30738986
+ }
+}
+</code></pre>
+</notextile>
+
+You can even make an input file directly executable the same way with the following two lines at the top:
+
+<notextile>
+<pre><code>#!/usr/bin/env cwl-runner
+cwl:tool: <span class="userinput">bwa-mem.cwl</span>
+</code></pre>
+</notextile>
+
+<notextile>
+<pre><code>~/arvados/doc/user/cwl/bwa-mem$ <span class="userinput">./bwa-mem-input.yml</span>
+arvados-cwl-runner 1.0.20160628195002, arvados-python-client 0.1.20160616015107, cwltool 1.0.20160629140624
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Upload local files: "bwa-mem.cwl"
+2016-06-30 14:56:36 arvados.arv-run[27002] INFO: Uploaded to qr1hi-4zz18-h7ljh5u76760ww2
+2016-06-30 14:56:40 arvados.cwl-runner[27002] INFO: Submitted job qr1hi-8i9sb-fm2n3b1w0l6bskg
+2016-06-30 14:56:41 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Running
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Job bwa-mem.cwl (qr1hi-8i9sb-fm2n3b1w0l6bskg) is Complete
+2016-06-30 14:57:12 arvados.cwl-runner[27002] INFO: Overall process status is success
+{
+ "aligned_sam": {
+ "path": "keep:54325254b226664960de07b3b9482349+154/HWI-ST1027_129_D0THKACXX.1_1.sam",
+ "checksum": "sha1$0dc46a3126d0b5d4ce213b5f0e86e2d05a54755a",
+ "class": "File",
+ "size": 30738986
+ }
+}
+</code></pre>
+</notextile>
."&& MEMLIMIT=\$(( (\$MEM * 95) / ($ENV{CRUNCH_NODE_SLOTS} * 100) )) "
."&& let SWAPLIMIT=\$MEMLIMIT+\$SWAP "
.q{&& declare -a VOLUMES=() }
- .q{&& if which crunchrunner >/dev/null ; then VOLUMES+=("--volume=$(which crunchrunner):/usr/local/bin/crunchrunner") ; fi }
- .q{&& if test -f /etc/ssl/certs/ca-certificates.crt ; then VOLUMES+=("--volume=/etc/ssl/certs/ca-certificates.crt:/etc/arvados/ca-certificates.crt") ; }
- .q{elif test -f /etc/pki/tls/certs/ca-bundle.crt ; then VOLUMES+=("--volume=/etc/pki/tls/certs/ca-bundle.crt:/etc/arvados/ca-certificates.crt") ; fi };
+ .q{&& if which crunchrunner >/dev/null ; then VOLUMES+=("--volume=$(which crunchrunner):/usr/local/bin/crunchrunner:ro") ; fi }
+ .q{&& if test -f /etc/ssl/certs/ca-certificates.crt ; then VOLUMES+=("--volume=/etc/ssl/certs/ca-certificates.crt:/etc/arvados/ca-certificates.crt:ro") ; }
+ .q{elif test -f /etc/pki/tls/certs/ca-bundle.crt ; then VOLUMES+=("--volume=/etc/pki/tls/certs/ca-bundle.crt:/etc/arvados/ca-certificates.crt:ro") ; fi };
$command .= "&& exec arv-mount --read-write --mount-by-pdh=by_pdh --mount-tmp=tmp --crunchstat-interval=10 --allow-other $arv_file_cache \Q$keep_mnt\E --exec ";
$ENV{TASK_KEEPMOUNT} = "$keep_mnt/by_pdh";
my $line = $1;
substr $jobstep[$jobstepidx]->{stderr}, 0, 1+length($line), "";
Log ($jobstepidx, "stderr $line");
- if ($line =~ /srun: error: (SLURM job $ENV{SLURM_JOB_ID} has expired|Unable to confirm allocation for job $ENV{SLURM_JOB_ID})/) {
+ if ($line =~ /srun: error: (SLURM job $ENV{SLURM_JOB_ID} has expired|Unable to confirm allocation for job $ENV{SLURM_JOB_ID})/i) {
# If the allocation is revoked, we can't possibly continue, so mark all
# nodes as failed. This will cause the overall exit code to be
# EX_RETRY_UNLOCKED instead of failure so that crunch_dispatch can re-run
$st->{node}->{fail_count}++;
}
}
- elsif ($line =~ /srun: error: (Node failure on|Aborting, .*\bio error\b)/) {
+ elsif ($line =~ /srun: error: .*?\b(Node failure on|Aborting, .*?\bio error\b)/i) {
$jobstep[$jobstepidx]->{tempfail} = 1;
if (defined($job_slot_index)) {
$slot[$job_slot_index]->{node}->{fail_count}++;
ban_node_by_slot($job_slot_index);
}
}
- elsif ($line =~ /srun: error: (Unable to create job step|.*: Communication connection failure)/) {
+ elsif ($line =~ /srun: error: (Unable to create job step|.*?: Communication connection failure)/i) {
$jobstep[$jobstepidx]->{tempfail} = 1;
ban_node_by_slot($job_slot_index) if (defined($job_slot_index));
}
close($log_pipe_in);
my $logger_failed = 0;
- my $read_result = log_writer_read_output(120);
+ my $read_result = log_writer_read_output(600);
if ($read_result == -1) {
$logger_failed = -1;
Log (undef, "timed out reading from 'arv-put'");
assert_match /^usage:/, err
end
+ def test_get_version
+ out, err = capture_subprocess_io do
+ assert_arv_get '--version'
+ end
+ assert_empty(out, "STDOUT not expected: '#{out}'")
+ assert_match(/[0-9]+\.[0-9]+\.[0-9]+/, err, "Version information incorrect: '#{err}'")
+ end
+
def test_help
out, err = capture_subprocess_io do
assert_arv_get '-h'
def test_raw_file
out, err = capture_subprocess_io do
- assert arv_put('--raw', './tmp/foo')
+ assert arv_put('--no-cache', '--raw', './tmp/foo')
end
$stderr.write err
assert_match '', err
def test_as_stream
out, err = capture_subprocess_io do
- assert arv_put('--as-stream', './tmp/foo')
+ assert arv_put('--no-cache', '--as-stream', './tmp/foo')
end
$stderr.write err
assert_match '', err
def test_progress
out, err = capture_subprocess_io do
- assert arv_put('--manifest', '--progress', './tmp/foo')
+ assert arv_put('--no-cache', '--manifest', '--progress', './tmp/foo')
end
assert_match /%/, err
assert match_collection_uuid(out)
def test_batch_progress
out, err = capture_subprocess_io do
- assert arv_put('--manifest', '--batch-progress', './tmp/foo')
+ assert arv_put('--no-cache', '--manifest', '--batch-progress', './tmp/foo')
end
assert_match /: 0 written 3 total/, err
assert_match /: 3 written 3 total/, err
from cwltool.errors import WorkflowException
import cwltool.main
import cwltool.workflow
+import cwltool.process
import schema_salad
+from schema_salad.sourceline import SourceLine
import arvados
import arvados.config
+from arvados.keep import KeepClient
+from arvados.errors import ApiError
from .arvcontainer import ArvadosContainer, RunnerContainer
from .arvjob import ArvadosJob, RunnerJob, RunnerTemplate
from. runner import Runner, upload_instance
from .arvtool import ArvadosCommandTool
from .arvworkflow import ArvadosWorkflow, upload_workflow
-from .fsaccess import CollectionFsAccess
+from .fsaccess import CollectionFsAccess, CollectionFetcher, collectionResolver
from .perf import Perf
from .pathmapper import FinalOutputPathMapper
from ._version import __version__
metrics = logging.getLogger('arvados.cwl-runner.metrics')
logger.setLevel(logging.INFO)
+arvados.log_handler.setFormatter(logging.Formatter(
+ '%(asctime)s %(name)s %(levelname)s: %(message)s',
+ '%Y-%m-%d %H:%M:%S'))
class ArvCwlRunner(object):
"""Execute a CWL tool or workflow, submit work (using either jobs or
"""
- def __init__(self, api_client, work_api=None, keep_client=None, output_name=None):
+ def __init__(self, api_client, work_api=None, keep_client=None, output_name=None, output_tags=None, num_retries=4):
self.api = api_client
self.processes = {}
self.lock = threading.Lock()
self.final_output = None
self.final_status = None
self.uploaded = {}
- self.num_retries = 4
+ self.num_retries = num_retries
self.uuid = None
self.stop_polling = threading.Event()
self.poll_api = None
self.pipeline = None
self.final_output_collection = None
self.output_name = output_name
+ self.output_tags = output_tags
self.project_uuid = None
if keep_client is not None:
else:
self.keep_client = arvados.keep.KeepClient(api_client=self.api, num_retries=self.num_retries)
- for api in ["jobs", "containers"]:
+ self.work_api = None
+ expected_api = ["jobs", "containers"]
+ for api in expected_api:
try:
methods = self.api._rootDesc.get('resources')[api]['methods']
if ('httpMethod' in methods['create'] and
break
except KeyError:
pass
+
if not self.work_api:
if work_api is None:
raise Exception("No supported APIs")
else:
- raise Exception("Unsupported API '%s'" % work_api)
+ raise Exception("Unsupported API '%s', expected one of %s" % (work_api, expected_api))
def arv_make_tool(self, toolpath_object, **kwargs):
kwargs["work_api"] = self.work_api
+ kwargs["fetcher_constructor"] = partial(CollectionFetcher,
+ api_client=self.api,
+ keep_client=self.keep_client)
if "class" in toolpath_object and toolpath_object["class"] == "CommandLineTool":
return ArvadosCommandTool(self, toolpath_object, **kwargs)
elif "class" in toolpath_object and toolpath_object["class"] == "Workflow":
uuid = event["object_uuid"]
with self.lock:
j = self.processes[uuid]
- logger.info("Job %s (%s) is Running", j.name, uuid)
+ logger.info("%s %s is Running", self.label(j), uuid)
j.running = True
j.update_pipeline_component(event["properties"]["new_attributes"])
- elif event["properties"]["new_attributes"]["state"] in ("Complete", "Failed", "Cancelled"):
+ elif event["properties"]["new_attributes"]["state"] in ("Complete", "Failed", "Cancelled", "Final"):
uuid = event["object_uuid"]
try:
self.cond.acquire()
j = self.processes[uuid]
- txt = self.work_api[0].upper() + self.work_api[1:-1]
- logger.info("%s %s (%s) is %s", txt, j.name, uuid, event["properties"]["new_attributes"]["state"])
+ logger.info("%s %s is %s", self.label(j), uuid, event["properties"]["new_attributes"]["state"])
with Perf(metrics, "done %s" % j.name):
j.done(event["properties"]["new_attributes"])
self.cond.notify()
finally:
self.cond.release()
+ def label(self, obj):
+ return "[%s %s]" % (self.work_api[0:-1], obj.name)
+
def poll_states(self):
"""Poll status of jobs or containers listed in the processes dict.
Runs in a separate thread.
"""
- while True:
- self.stop_polling.wait(15)
- if self.stop_polling.is_set():
- break
- with self.lock:
- keys = self.processes.keys()
- if not keys:
- continue
+ try:
+ while True:
+ self.stop_polling.wait(15)
+ if self.stop_polling.is_set():
+ break
+ with self.lock:
+ keys = self.processes.keys()
+ if not keys:
+ continue
- if self.work_api == "containers":
- table = self.poll_api.containers()
- elif self.work_api == "jobs":
- table = self.poll_api.jobs()
+ if self.work_api == "containers":
+ table = self.poll_api.container_requests()
+ elif self.work_api == "jobs":
+ table = self.poll_api.jobs()
- try:
- proc_states = table.list(filters=[["uuid", "in", keys]]).execute(num_retries=self.num_retries)
- except Exception as e:
- logger.warn("Error checking states on API server: %s", e)
- continue
-
- for p in proc_states["items"]:
- self.on_message({
- "object_uuid": p["uuid"],
- "event_type": "update",
- "properties": {
- "new_attributes": p
- }
- })
+ try:
+ proc_states = table.list(filters=[["uuid", "in", keys]]).execute(num_retries=self.num_retries)
+ except Exception as e:
+ logger.warn("Error checking states on API server: %s", e)
+ continue
+
+ for p in proc_states["items"]:
+ self.on_message({
+ "object_uuid": p["uuid"],
+ "event_type": "update",
+ "properties": {
+ "new_attributes": p
+ }
+ })
+ except:
+ logger.error("Fatal error in state polling thread.", exc_info=(sys.exc_info()[1] if self.debug else False))
+ self.cond.acquire()
+ self.processes.clear()
+ self.cond.notify()
+ self.cond.release()
+ finally:
+ self.stop_polling.set()
def get_uploaded(self):
return self.uploaded.copy()
def add_uploaded(self, src, pair):
self.uploaded[src] = pair
- def check_writable(self, obj):
+ def check_features(self, obj):
if isinstance(obj, dict):
+ if obj.get("class") == "InitialWorkDirRequirement":
+ if self.work_api == "containers":
+ raise UnsupportedRequirement("InitialWorkDirRequirement not supported with --api=containers")
if obj.get("writable"):
- raise UnsupportedRequirement("InitialWorkDir feature 'writable: true' not supported")
+ raise SourceLine(obj, "writable", UnsupportedRequirement).makeError("InitialWorkDir feature 'writable: true' not supported")
+ if obj.get("class") == "CommandLineTool":
+ if self.work_api == "containers":
+ if obj.get("stdin"):
+ raise SourceLine(obj, "stdin", UnsupportedRequirement).makeError("Stdin redirection currently not suppported with --api=containers")
+ if obj.get("stderr"):
+ raise SourceLine(obj, "stderr", UnsupportedRequirement).makeError("Stderr redirection currently not suppported with --api=containers")
for v in obj.itervalues():
- self.check_writable(v)
- if isinstance(obj, list):
- for v in obj:
- self.check_writable(v)
+ self.check_features(v)
+ elif isinstance(obj, list):
+ for i,v in enumerate(obj):
+ with SourceLine(obj, i, UnsupportedRequirement):
+ self.check_features(v)
- def make_output_collection(self, name, outputObj):
+ def make_output_collection(self, name, tagsString, outputObj):
outputObj = copy.deepcopy(outputObj)
files = []
final.api_response()["name"],
final.manifest_locator())
+ final_uuid = final.manifest_locator()
+ tags = tagsString.split(',')
+ for tag in tags:
+ self.api.links().create(body={
+ "head_uuid": final_uuid, "link_class": "tag", "name": tag
+ }).execute(num_retries=self.num_retries)
+
def finalcollection(fileobj):
fileobj["location"] = "keep:%s/%s" % (final.portable_data_hash(), fileobj["location"])
if self.work_api == "containers":
try:
current = self.api.containers().current().execute(num_retries=self.num_retries)
+ except ApiError as e:
+ # Status code 404 just means we're not running in a container.
+ if e.resp.status != 404:
+ logger.info("Getting current container: %s", e)
+ return
+ try:
self.api.containers().update(uuid=current['uuid'],
body={
'output': self.final_output_collection.portable_data_hash(),
def arv_executor(self, tool, job_order, **kwargs):
self.debug = kwargs.get("debug")
- tool.visit(self.check_writable)
+ tool.visit(self.check_features)
- useruuid = self.api.users().current().execute()["uuid"]
- self.project_uuid = kwargs.get("project_uuid") if kwargs.get("project_uuid") else useruuid
+ self.project_uuid = kwargs.get("project_uuid")
self.pipeline = None
make_fs_access = kwargs.get("make_fs_access") or partial(CollectionFsAccess,
api_client=self.api,
keep_client=self.keep_client)
self.fs_access = make_fs_access(kwargs["basedir"])
- if kwargs.get("create_template"):
- tmpl = RunnerTemplate(self, tool, job_order, kwargs.get("enable_reuse"))
- tmpl.save()
- # cwltool.main will write our return value to stdout.
- return tmpl.uuid
-
- if kwargs.get("create_workflow") or kwargs.get("update_workflow"):
- return upload_workflow(self, tool, job_order, self.project_uuid, kwargs.get("update_workflow"))
+ existing_uuid = kwargs.get("update_workflow")
+ if existing_uuid or kwargs.get("create_workflow"):
+ if self.work_api == "jobs":
+ tmpl = RunnerTemplate(self, tool, job_order,
+ kwargs.get("enable_reuse"),
+ uuid=existing_uuid,
+ submit_runner_ram=kwargs.get("submit_runner_ram"),
+ name=kwargs.get("name"))
+ tmpl.save()
+ # cwltool.main will write our return value to stdout.
+ return (tmpl.uuid, "success")
+ else:
+ return (upload_workflow(self, tool, job_order,
+ self.project_uuid,
+ uuid=existing_uuid,
+ submit_runner_ram=kwargs.get("submit_runner_ram"),
+ name=kwargs.get("name")), "success")
self.ignore_docker_for_reuse = kwargs.get("ignore_docker_for_reuse")
kwargs["enable_reuse"] = kwargs.get("enable_reuse")
kwargs["use_container"] = True
kwargs["tmpdir_prefix"] = "tmp"
- kwargs["on_error"] = "continue"
kwargs["compute_checksum"] = kwargs.get("compute_checksum")
+ if not kwargs["name"]:
+ del kwargs["name"]
+
if self.work_api == "containers":
kwargs["outdir"] = "/var/spool/cwl"
kwargs["docker_outdir"] = "/var/spool/cwl"
if kwargs.get("submit"):
if self.work_api == "containers":
if tool.tool["class"] == "CommandLineTool":
+ kwargs["runnerjob"] = tool.tool["id"]
runnerjob = tool.job(job_order,
self.output_callback,
**kwargs).next()
else:
- runnerjob = RunnerContainer(self, tool, job_order, kwargs.get("enable_reuse"), self.output_name)
+ runnerjob = RunnerContainer(self, tool, job_order, kwargs.get("enable_reuse"), self.output_name,
+ self.output_tags, submit_runner_ram=kwargs.get("submit_runner_ram"),
+ name=kwargs.get("name"), on_error=kwargs.get("on_error"))
else:
- runnerjob = RunnerJob(self, tool, job_order, kwargs.get("enable_reuse"), self.output_name)
+ runnerjob = RunnerJob(self, tool, job_order, kwargs.get("enable_reuse"), self.output_name,
+ self.output_tags, submit_runner_ram=kwargs.get("submit_runner_ram"),
+ name=kwargs.get("name"), on_error=kwargs.get("on_error"))
if not kwargs.get("submit") and "cwl_runner_job" not in kwargs and not self.work_api == "containers":
# Create pipeline for local run
self.pipeline = self.api.pipeline_instances().create(
body={
"owner_uuid": self.project_uuid,
- "name": shortname(tool.tool["id"]),
+ "name": kwargs["name"] if kwargs.get("name") else shortname(tool.tool["id"]),
"components": {},
"state": "RunningOnClient"}).execute(num_retries=self.num_retries)
logger.info("Pipeline instance %s", self.pipeline["uuid"])
if runnerjob and not kwargs.get("wait"):
runnerjob.run(wait=kwargs.get("wait"))
- return runnerjob.uuid
+ return (runnerjob.uuid, "success")
self.poll_api = arvados.api('v1')
self.polling_thread = threading.Thread(target=self.poll_states)
loopperf.__enter__()
for runnable in jobiter:
loopperf.__exit__()
+
+ if self.stop_polling.is_set():
+ break
+
if runnable:
with Perf(metrics, "run"):
runnable.run(**kwargs)
if sys.exc_info()[0] is KeyboardInterrupt:
logger.error("Interrupted, marking pipeline as failed")
else:
- logger.error("Caught unhandled exception, marking pipeline as failed. Error was: %s", sys.exc_info()[1], exc_info=(sys.exc_info()[1] if self.debug else False))
+ logger.error("Execution failed: %s", sys.exc_info()[1], exc_info=(sys.exc_info()[1] if self.debug else False))
if self.pipeline:
self.api.pipeline_instances().update(uuid=self.pipeline["uuid"],
body={"state": "Failed"}).execute(num_retries=self.num_retries)
else:
if self.output_name is None:
self.output_name = "Output of %s" % (shortname(tool.tool["id"]))
- self.final_output, self.final_output_collection = self.make_output_collection(self.output_name, self.final_output)
+ if self.output_tags is None:
+ self.output_tags = ""
+ self.final_output, self.final_output_collection = self.make_output_collection(self.output_name, self.output_tags, self.final_output)
self.set_crunch_output()
- if self.final_status != "success":
- raise WorkflowException("Workflow failed.")
-
if kwargs.get("compute_checksum"):
adjustDirObjs(self.final_output, partial(getListing, self.fs_access))
adjustFileObjs(self.final_output, partial(compute_checksums, self.fs_access))
- return self.final_output
+ return (self.final_output, self.final_status)
def versionstring():
parser.add_argument("--project-uuid", type=str, metavar="UUID", help="Project that will own the workflow jobs, if not provided, will go to home project.")
parser.add_argument("--output-name", type=str, help="Name to use for collection that stores the final output.", default=None)
+ parser.add_argument("--output-tags", type=str, help="Tags for the final output collection separated by commas, e.g., '--output-tags tag0,tag1,tag2'.", default=None)
parser.add_argument("--ignore-docker-for-reuse", action="store_true",
help="Ignore Docker image version when deciding whether to reuse past jobs.",
default=False)
default=True, dest="submit")
exgroup.add_argument("--local", action="store_false", help="Run workflow on local host (submits jobs to Arvados).",
default=True, dest="submit")
- exgroup.add_argument("--create-template", action="store_true", help="Create an Arvados pipeline template.")
- exgroup.add_argument("--create-workflow", action="store_true", help="Create an Arvados workflow.")
- exgroup.add_argument("--update-workflow", type=str, metavar="UUID", help="Update existing Arvados workflow with uuid.")
+ exgroup.add_argument("--create-template", action="store_true", help="(Deprecated) synonym for --create-workflow.",
+ dest="create_workflow")
+ exgroup.add_argument("--create-workflow", action="store_true", help="Create an Arvados workflow (if using the 'containers' API) or pipeline template (if using the 'jobs' API). See --api.")
+ exgroup.add_argument("--update-workflow", type=str, metavar="UUID", help="Update an existing Arvados workflow or pipeline template with the given UUID.")
exgroup = parser.add_mutually_exclusive_group()
exgroup.add_argument("--wait", action="store_true", help="After submitting workflow runner job, wait for completion.",
exgroup.add_argument("--no-wait", action="store_false", help="Submit workflow runner job and exit.",
default=True, dest="wait")
+ exgroup = parser.add_mutually_exclusive_group()
+ exgroup.add_argument("--log-timestamps", action="store_true", help="Prefix logging lines with timestamp",
+ default=True, dest="log_timestamps")
+ exgroup.add_argument("--no-log-timestamps", action="store_false", help="No timestamp on logging lines",
+ default=True, dest="log_timestamps")
+
parser.add_argument("--api", type=str,
default=None, dest="work_api",
help="Select work submission API, one of 'jobs' or 'containers'. Default is 'jobs' if that API is available, otherwise 'containers'.")
help="Compute checksum of contents while collecting outputs",
dest="compute_checksum")
+ parser.add_argument("--submit-runner-ram", type=int,
+ help="RAM (in MiB) required for the workflow runner job (default 1024)",
+ default=1024)
+
+ parser.add_argument("--name", type=str,
+ help="Name to use for workflow execution instance.",
+ default=None)
+
+ parser.add_argument("--on-error", type=str,
+ help="Desired workflow behavior when a step fails. One of 'stop' or 'continue'. "
+ "Default is 'continue'.", default="continue", choices=("stop", "continue"))
+
parser.add_argument("workflow", type=str, nargs="?", default=None, help="The workflow to execute")
parser.add_argument("job_order", nargs=argparse.REMAINDER, help="The input object to the workflow.")
job_order_object = None
arvargs = parser.parse_args(args)
- if (arvargs.create_template or arvargs.create_workflow or arvargs.update_workflow) and not arvargs.job_order:
+
+ if arvargs.version:
+ print versionstring()
+ return
+
+ if arvargs.update_workflow:
+ if arvargs.update_workflow.find('-7fd4e-') == 5:
+ want_api = 'containers'
+ elif arvargs.update_workflow.find('-p5p6p-') == 5:
+ want_api = 'jobs'
+ else:
+ want_api = None
+ if want_api and arvargs.work_api and want_api != arvargs.work_api:
+ logger.error('--update-workflow arg {!r} uses {!r} API, but --api={!r} specified'.format(
+ arvargs.update_workflow, want_api, arvargs.work_api))
+ return 1
+ arvargs.work_api = want_api
+
+ if (arvargs.create_workflow or arvargs.update_workflow) and not arvargs.job_order:
job_order_object = ({}, "")
add_arv_hints()
try:
if api_client is None:
api_client=arvados.api('v1', model=OrderedJsonModel())
- runner = ArvCwlRunner(api_client, work_api=arvargs.work_api, keep_client=keep_client, output_name=arvargs.output_name)
+ if keep_client is None:
+ keep_client = arvados.keep.KeepClient(api_client=api_client, num_retries=4)
+ runner = ArvCwlRunner(api_client, work_api=arvargs.work_api, keep_client=keep_client,
+ num_retries=4, output_name=arvargs.output_name,
+ output_tags=arvargs.output_tags)
except Exception as e:
logger.error(e)
return 1
metrics.setLevel(logging.DEBUG)
logging.getLogger("cwltool.metrics").setLevel(logging.DEBUG)
+ if arvargs.log_timestamps:
+ arvados.log_handler.setFormatter(logging.Formatter(
+ '%(asctime)s %(name)s %(levelname)s: %(message)s',
+ '%Y-%m-%d %H:%M:%S'))
+ else:
+ arvados.log_handler.setFormatter(logging.Formatter('%(name)s %(levelname)s: %(message)s'))
+
arvargs.conformance_test = None
arvargs.use_container = True
+ arvargs.relax_path_checks = True
+ arvargs.validate = None
return cwltool.main.main(args=arvargs,
stdout=stdout,
makeTool=runner.arv_make_tool,
versionfunc=versionstring,
job_order_object=job_order_object,
- make_fs_access=partial(CollectionFsAccess, api_client=api_client))
+ make_fs_access=partial(CollectionFsAccess,
+ api_client=api_client,
+ keep_client=keep_client),
+ fetcher_constructor=partial(CollectionFetcher,
+ api_client=api_client,
+ keep_client=keep_client),
+ resolver=partial(collectionResolver, api_client),
+ logger_handler=arvados.log_handler)
import json
import os
+import ruamel.yaml as yaml
+
from cwltool.errors import WorkflowException
from cwltool.process import get_feature, UnsupportedRequirement, shortname
from cwltool.pathmapper import adjustFiles
from .arvdocker import arv_docker_get_image
from . import done
from .runner import Runner, arvados_jobs_image
+from .fsaccess import CollectionFetcher
logger = logging.getLogger('arvados.cwl-runner')
"output_path": self.outdir,
"cwd": self.outdir,
"priority": 1,
- "state": "Committed"
+ "state": "Committed",
+ "properties": {}
}
runtime_constraints = {}
mounts = {
"kind": "tmp"
}
}
+ scheduling_parameters = {}
dirs = set()
for f in self.pathmapper.files():
}
if self.generatefiles["listing"]:
- raise UnsupportedRequirement("Generate files not supported")
+ raise UnsupportedRequirement("InitialWorkDirRequirement not supported with --api=containers")
container_request["environment"] = {"TMPDIR": self.tmpdir, "HOME": self.outdir}
if self.environment:
partition_req, _ = get_feature(self, "http://arvados.org/cwl#PartitionRequirement")
if partition_req:
- runtime_constraints["partition"] = aslist(partition_req["partition"])
+ scheduling_parameters["partitions"] = aslist(partition_req["partition"])
container_request["mounts"] = mounts
container_request["runtime_constraints"] = runtime_constraints
container_request["use_existing"] = kwargs.get("enable_reuse", True)
+ container_request["scheduling_parameters"] = scheduling_parameters
+
+ if kwargs.get("runnerjob", "").startswith("arvwf:"):
+ wfuuid = kwargs["runnerjob"][6:kwargs["runnerjob"].index("#")]
+ wfrecord = self.arvrunner.api.workflows().get(uuid=wfuuid).execute(num_retries=self.arvrunner.num_retries)
+ if container_request["name"] == "main":
+ container_request["name"] = wfrecord["name"]
+ container_request["properties"]["template_uuid"] = wfuuid
try:
response = self.arvrunner.api.container_requests().create(
body=container_request
).execute(num_retries=self.arvrunner.num_retries)
- self.arvrunner.processes[response["container_uuid"]] = self
-
- container = self.arvrunner.api.containers().get(
- uuid=response["container_uuid"]
- ).execute(num_retries=self.arvrunner.num_retries)
+ self.uuid = response["uuid"]
+ self.arvrunner.processes[self.uuid] = self
- logger.info("Container request %s (%s) state is %s with container %s %s", self.name, response["uuid"], response["state"], container["uuid"], container["state"])
+ logger.info("%s %s state is %s", self.arvrunner.label(self), response["uuid"], response["state"])
- if container["state"] in ("Complete", "Cancelled"):
- self.done(container)
+ if response["state"] == "Final":
+ self.done(response)
except Exception as e:
- logger.error("Got error %s" % str(e))
+ logger.error("%s got error %s" % (self.arvrunner.label(self), str(e)))
self.output_callback({}, "permanentFail")
def done(self, record):
try:
- if record["state"] == "Complete":
- rcode = record["exit_code"]
+ container = self.arvrunner.api.containers().get(
+ uuid=record["container_uuid"]
+ ).execute(num_retries=self.arvrunner.num_retries)
+ if container["state"] == "Complete":
+ rcode = container["exit_code"]
if self.successCodes and rcode in self.successCodes:
processStatus = "success"
elif self.temporaryFailCodes and rcode in self.temporaryFailCodes:
else:
processStatus = "permanentFail"
- try:
- outputs = {}
- if record["output"]:
- outputs = done.done(self, record, "/tmp", self.outdir, "/keep")
- except WorkflowException as e:
- logger.error("Error while collecting container outputs:\n%s", e, exc_info=(e if self.arvrunner.debug else False))
- processStatus = "permanentFail"
- except Exception as e:
- logger.exception("Got unknown exception while collecting job outputs:")
- processStatus = "permanentFail"
-
- self.output_callback(outputs, processStatus)
+ if processStatus == "permanentFail":
+ logc = arvados.collection.CollectionReader(container["log"],
+ api_client=self.arvrunner.api,
+ keep_client=self.arvrunner.keep_client,
+ num_retries=self.arvrunner.num_retries)
+ done.logtail(logc, logger, "%s error log:" % self.arvrunner.label(self))
+
+ outputs = {}
+ if container["output"]:
+ outputs = done.done_outputs(self, container, "/tmp", self.outdir, "/keep")
+ except WorkflowException as e:
+ logger.error("%s unable to collect output from %s:\n%s",
+ self.arvrunner.label(self), container["output"], e, exc_info=(e if self.arvrunner.debug else False))
+ processStatus = "permanentFail"
+ except Exception as e:
+ logger.exception("%s while getting output object: %s", self.arvrunner.label(self), e)
+ processStatus = "permanentFail"
finally:
- del self.arvrunner.processes[record["uuid"]]
+ self.output_callback(outputs, processStatus)
+ if record["uuid"] in self.arvrunner.processes:
+ del self.arvrunner.processes[record["uuid"]]
class RunnerContainer(Runner):
workflowmapper = super(RunnerContainer, self).arvados_job_spec(dry_run=dry_run, pull_image=pull_image, **kwargs)
- with arvados.collection.Collection(api_client=self.arvrunner.api,
- keep_client=self.arvrunner.keep_client,
- num_retries=self.arvrunner.num_retries) as jobobj:
- with jobobj.open("cwl.input.json", "w") as f:
- json.dump(self.job_order, f, sort_keys=True, indent=4)
- jobobj.save_new(owner_uuid=self.arvrunner.project_uuid)
-
- workflowname = os.path.basename(self.tool.tool["id"])
- workflowpath = "/var/lib/cwl/workflow/%s" % workflowname
- workflowcollection = workflowmapper.mapper(self.tool.tool["id"])[1]
- workflowcollection = workflowcollection[5:workflowcollection.index('/')]
- jobpath = "/var/lib/cwl/job/cwl.input.json"
-
- command = ["arvados-cwl-runner", "--local", "--api=containers"]
- if self.output_name:
- command.append("--output-name=" + self.output_name)
-
- if self.enable_reuse:
- command.append("--enable-reuse")
- else:
- command.append("--disable-reuse")
-
- command.extend([workflowpath, jobpath])
-
- return {
- "command": command,
+ container_req = {
"owner_uuid": self.arvrunner.project_uuid,
"name": self.name,
"output_path": "/var/spool/cwl",
"state": "Committed",
"container_image": arvados_jobs_image(self.arvrunner),
"mounts": {
- "/var/lib/cwl/workflow": {
- "kind": "collection",
- "portable_data_hash": "%s" % workflowcollection
- },
- jobpath: {
- "kind": "collection",
- "portable_data_hash": "%s/cwl.input.json" % jobobj.portable_data_hash()
+ "/var/lib/cwl/cwl.input.json": {
+ "kind": "json",
+ "content": self.job_order
},
"stdout": {
"kind": "file",
},
"runtime_constraints": {
"vcpus": 1,
- "ram": 1024*1024*256,
+ "ram": 1024*1024 * self.submit_runner_ram,
"API": True
- }
+ },
+ "properties": {}
}
+ workflowcollection = workflowmapper.mapper(self.tool.tool["id"])[1]
+ if workflowcollection.startswith("keep:"):
+ workflowcollection = workflowcollection[5:workflowcollection.index('/')]
+ workflowname = os.path.basename(self.tool.tool["id"])
+ workflowpath = "/var/lib/cwl/workflow/%s" % workflowname
+ container_req["mounts"]["/var/lib/cwl/workflow"] = {
+ "kind": "collection",
+ "portable_data_hash": "%s" % workflowcollection
+ }
+ elif workflowcollection.startswith("arvwf:"):
+ workflowpath = "/var/lib/cwl/workflow.json#main"
+ wfuuid = workflowcollection[6:workflowcollection.index("#")]
+ wfrecord = self.arvrunner.api.workflows().get(uuid=wfuuid).execute(num_retries=self.arvrunner.num_retries)
+ wfobj = yaml.safe_load(wfrecord["definition"])
+ if container_req["name"].startswith("arvwf:"):
+ container_req["name"] = wfrecord["name"]
+ container_req["mounts"]["/var/lib/cwl/workflow.json"] = {
+ "kind": "json",
+ "json": wfobj
+ }
+ container_req["properties"]["template_uuid"] = wfuuid
+
+ command = ["arvados-cwl-runner", "--local", "--api=containers", "--no-log-timestamps"]
+ if self.output_name:
+ command.append("--output-name=" + self.output_name)
+ container_req["output_name"] = self.output_name
+
+ if self.output_tags:
+ command.append("--output-tags=" + self.output_tags)
+
+ if kwargs.get("debug"):
+ command.append("--debug")
+
+ if self.enable_reuse:
+ command.append("--enable-reuse")
+ else:
+ command.append("--disable-reuse")
+
+ if self.on_error:
+ command.append("--on-error=" + self.on_error)
+
+ command.extend([workflowpath, "/var/lib/cwl/cwl.input.json"])
+
+ container_req["command"] = command
+
+ return container_req
+
+
def run(self, *args, **kwargs):
kwargs["keepprefix"] = "keep:"
job_spec = self.arvados_job_spec(*args, **kwargs)
).execute(num_retries=self.arvrunner.num_retries)
self.uuid = response["uuid"]
- self.arvrunner.processes[response["container_uuid"]] = self
+ self.arvrunner.processes[self.uuid] = self
- logger.info("Submitted container %s", response["uuid"])
+ logger.info("%s submitted container %s", self.arvrunner.label(self), response["uuid"])
- if response["state"] in ("Complete", "Failed", "Cancelled"):
+ if response["state"] == "Final":
self.done(response)
+
+ def done(self, record):
+ try:
+ container = self.arvrunner.api.containers().get(
+ uuid=record["container_uuid"]
+ ).execute(num_retries=self.arvrunner.num_retries)
+ except Exception as e:
+ logger.exception("%s while getting runner container: %s", self.arvrunner.label(self), e)
+ self.arvrunner.output_callback({}, "permanentFail")
+ else:
+ super(RunnerContainer, self).done(container)
+ finally:
+ if record["uuid"] in self.arvrunner.processes:
+ del self.arvrunner.processes[record["uuid"]]
import sys
import threading
+from schema_salad.sourceline import SourceLine
+
import cwltool.docker
from cwltool.errors import WorkflowException
import arvados.commands.keepdocker
if "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement:
dockerRequirement["dockerImageId"] = dockerRequirement["dockerPull"]
+ if hasattr(dockerRequirement, 'lc'):
+ dockerRequirement.lc.data["dockerImageId"] = dockerRequirement.lc.data["dockerPull"]
global cached_lookups
global cached_lookups_lock
if dockerRequirement["dockerImageId"] in cached_lookups:
return cached_lookups[dockerRequirement["dockerImageId"]]
- sp = dockerRequirement["dockerImageId"].split(":")
- image_name = sp[0]
- image_tag = sp[1] if len(sp) > 1 else None
-
- images = arvados.commands.keepdocker.list_images_in_arv(api_client, 3,
- image_name=image_name,
- image_tag=image_tag)
-
- if not images:
- # Fetch Docker image if necessary.
- cwltool.docker.get_image(dockerRequirement, pull_image)
-
- # Upload image to Arvados
- args = ["--project-uuid="+project_uuid, image_name]
- if image_tag:
- args.append(image_tag)
- logger.info("Uploading Docker image %s", ":".join(args[1:]))
- try:
- arvados.commands.keepdocker.main(args, stdout=sys.stderr)
- except SystemExit as e:
- if e.code:
- raise WorkflowException("keepdocker exited with code %s" % e.code)
+ with SourceLine(dockerRequirement, "dockerImageId", WorkflowException):
+ sp = dockerRequirement["dockerImageId"].split(":")
+ image_name = sp[0]
+ image_tag = sp[1] if len(sp) > 1 else None
images = arvados.commands.keepdocker.list_images_in_arv(api_client, 3,
image_name=image_name,
image_tag=image_tag)
- if not images:
- raise WorkflowException("Could not find Docker image %s:%s" % (image_name, image_tag))
-
- pdh = api_client.collections().get(uuid=images[0][0]).execute()["portable_data_hash"]
-
- with cached_lookups_lock:
- cached_lookups[dockerRequirement["dockerImageId"]] = pdh
-
- return pdh
+ if not images:
+ # Fetch Docker image if necessary.
+ cwltool.docker.get_image(dockerRequirement, pull_image)
+
+ # Upload image to Arvados
+ args = []
+ if project_uuid:
+ args.append("--project-uuid="+project_uuid)
+ args.append(image_name)
+ if image_tag:
+ args.append(image_tag)
+ logger.info("Uploading Docker image %s", ":".join(args[1:]))
+ try:
+ arvados.commands.keepdocker.main(args, stdout=sys.stderr)
+ except SystemExit as e:
+ if e.code:
+ raise WorkflowException("keepdocker exited with code %s" % e.code)
+
+ images = arvados.commands.keepdocker.list_images_in_arv(api_client, 3,
+ image_name=image_name,
+ image_tag=image_tag)
+
+ if not images:
+ raise WorkflowException("Could not find Docker image %s:%s" % (image_name, image_tag))
+
+ pdh = api_client.collections().get(uuid=images[0][0]).execute()["portable_data_hash"]
+
+ with cached_lookups_lock:
+ cached_lookups[dockerRequirement["dockerImageId"]] = pdh
+
+ return pdh
def arv_docker_clear_cache():
global cached_lookups
crunchrunner_re = re.compile(r"^\S+ \S+ \d+ \d+ stderr \S+ \S+ crunchrunner: \$\(task\.(tmpdir|outdir|keep)\)=(.*)")
+crunchrunner_git_commit = 'a3f2cb186e437bfce0031b024b2157b73ed2717d'
+
class ArvadosJob(object):
"""Submit and manage a Crunch job for executing a CWL CommandLineTool."""
(docker_req, docker_is_req) = get_feature(self, "DockerRequirement")
if docker_req and kwargs.get("use_container") is not False:
if docker_req.get("dockerOutputDirectory"):
- raise UnsupportedRequirement("Option 'dockerOutputDirectory' of DockerRequirement not supported.")
+ raise SourceLine(docker_req, "dockerOutputDirectory", UnsupportedRequirement).makeError(
+ "Option 'dockerOutputDirectory' of DockerRequirement not supported.")
runtime_constraints["docker_image"] = arv_docker_get_image(self.arvrunner.api, docker_req, pull_image, self.arvrunner.project_uuid)
else:
runtime_constraints["docker_image"] = arvados_jobs_image(self.arvrunner)
filters = [["repository", "=", "arvados"],
["script", "=", "crunchrunner"],
- ["script_version", "in git", "9e5b98e8f5f4727856b53447191f9c06e3da2ba6"]]
+ ["script_version", "in git", crunchrunner_git_commit]]
if not self.arvrunner.ignore_docker_for_reuse:
filters.append(["docker_image_locator", "in docker", runtime_constraints["docker_image"]])
"script": "crunchrunner",
"repository": "arvados",
"script_version": "master",
- "minimum_script_version": "9e5b98e8f5f4727856b53447191f9c06e3da2ba6",
+ "minimum_script_version": crunchrunner_git_commit,
"script_parameters": {"tasks": [script_parameters]},
"runtime_constraints": runtime_constraints
},
self.update_pipeline_component(response)
- logger.info("Job %s (%s) is %s", self.name, response["uuid"], response["state"])
+ logger.info("%s %s is %s", self.arvrunner.label(self), response["uuid"], response["state"])
if response["state"] in ("Complete", "Failed", "Cancelled"):
with Perf(metrics, "done %s" % self.name):
self.done(response)
except Exception as e:
- logger.error("Got error %s" % str(e))
+ logger.exception("%s error" % (self.arvrunner.label(self)))
self.output_callback({}, "permanentFail")
def update_pipeline_component(self, record):
if g:
dirs[g.group(1)] = g.group(2)
+ if processStatus == "permanentFail":
+ done.logtail(logc, logger, "%s error log:" % self.arvrunner.label(self))
+
with Perf(metrics, "output collection %s" % self.name):
outputs = done.done(self, record, dirs["tmpdir"],
dirs["outdir"], dirs["keep"])
except WorkflowException as e:
- logger.error("Error while collecting job outputs:\n%s", e, exc_info=(e if self.arvrunner.debug else False))
+ logger.error("%s unable to collect output from %s:\n%s",
+ self.arvrunner.label(self), record["output"], e, exc_info=(e if self.arvrunner.debug else False))
processStatus = "permanentFail"
- outputs = None
except Exception as e:
- logger.exception("Got unknown exception while collecting job outputs:")
+ logger.exception("Got unknown exception while collecting output for job %s:", self.name)
processStatus = "permanentFail"
- outputs = None
- self.output_callback(outputs, processStatus)
+ # Note: Currently, on error output_callback is expecting an empty dict,
+ # anything else will fail.
+ if not isinstance(outputs, dict):
+ logger.error("Unexpected output type %s '%s'", type(outputs), outputs)
+ outputs = {}
+ processStatus = "permanentFail"
finally:
- del self.arvrunner.processes[record["uuid"]]
-
+ self.output_callback(outputs, processStatus)
+ if record["uuid"] in self.arvrunner.processes:
+ del self.arvrunner.processes[record["uuid"]]
class RunnerJob(Runner):
"""Submit and manage a Crunch job that runs crunch_scripts/cwl-runner."""
workflowmapper = super(RunnerJob, self).arvados_job_spec(dry_run=dry_run, pull_image=pull_image, **kwargs)
- # Need to filter this out, gets added by cwltool when providing
- # parameters on the command line, and arv-run-pipeline-instance doesn't
- # like it.
- if "job_order" in self.job_order:
- del self.job_order["job_order"]
-
self.job_order["cwl:tool"] = workflowmapper.mapper(self.tool.tool["id"]).target[5:]
if self.output_name:
self.job_order["arv:output_name"] = self.output_name
+ if self.output_tags:
+ self.job_order["arv:output_tags"] = self.output_tags
+
self.job_order["arv:enable_reuse"] = self.enable_reuse
+ if self.on_error:
+ self.job_order["arv:on_error"] = self.on_error
+
return {
"script": "cwl-runner",
- "script_version": __version__,
+ "script_version": "master",
+ "minimum_script_version": "570509ab4d2ef93d870fd2b1f2eab178afb1bad9",
"repository": "arvados",
"script_parameters": self.job_order,
"runtime_constraints": {
- "docker_image": arvados_jobs_image(self.arvrunner)
+ "docker_image": arvados_jobs_image(self.arvrunner),
+ "min_ram_mb_per_node": self.submit_runner_ram
}
}
self.arvrunner.pipeline = self.arvrunner.api.pipeline_instances().create(
body={
"owner_uuid": self.arvrunner.project_uuid,
- "name": shortname(self.tool.tool["id"]),
+ "name": self.name,
"components": {"cwl-runner": job_spec },
"state": "RunningOnServer"}).execute(num_retries=self.arvrunner.num_retries)
logger.info("Created pipeline %s", self.arvrunner.pipeline["uuid"])
'string': 'text',
}
- def __init__(self, runner, tool, job_order, enable_reuse):
+ def __init__(self, runner, tool, job_order, enable_reuse, uuid,
+ submit_runner_ram=0, name=None):
self.runner = runner
self.tool = tool
self.job = RunnerJob(
tool=tool,
job_order=job_order,
enable_reuse=enable_reuse,
- output_name=None)
+ output_name=None,
+ output_tags=None,
+ submit_runner_ram=submit_runner_ram,
+ name=name)
+ self.uuid = uuid
def pipeline_component_spec(self):
"""Return a component that Workbench and a-r-p-i will understand.
return spec
def save(self):
- job_spec = self.pipeline_component_spec()
- response = self.runner.api.pipeline_templates().create(body={
+ body = {
"components": {
- self.job.name: job_spec,
+ self.job.name: self.pipeline_component_spec(),
},
"name": self.job.name,
- "owner_uuid": self.runner.project_uuid,
- }, ensure_unique_name=True).execute(num_retries=self.runner.num_retries)
- self.uuid = response["uuid"]
- logger.info("Created template %s", self.uuid)
+ }
+ if self.runner.project_uuid:
+ body["owner_uuid"] = self.runner.project_uuid
+ if self.uuid:
+ self.runner.api.pipeline_templates().update(
+ uuid=self.uuid, body=body).execute(
+ num_retries=self.runner.num_retries)
+ logger.info("Updated template %s", self.uuid)
+ else:
+ self.uuid = self.runner.api.pipeline_templates().create(
+ body=body, ensure_unique_name=True).execute(
+ num_retries=self.runner.num_retries)['uuid']
+ logger.info("Created template %s", self.uuid)
import copy
import logging
+from schema_salad.sourceline import SourceLine, cmap
+
from cwltool.pack import pack
from cwltool.load_tool import fetch_document
from cwltool.process import shortname
logger = logging.getLogger('arvados.cwl-runner')
metrics = logging.getLogger('arvados.cwl-runner.metrics')
-def upload_workflow(arvRunner, tool, job_order, project_uuid, update_uuid):
+def upload_workflow(arvRunner, tool, job_order, project_uuid, uuid=None,
+ submit_runner_ram=0, name=None):
upload_docker(arvRunner, tool)
document_loader, workflowobj, uri = (tool.doc_loader, tool.doc_loader.fetch(tool.tool["id"]), tool.tool["id"])
if sn in job_order:
inp["default"] = job_order[sn]
- name = os.path.basename(tool.tool["id"])
+ if not name:
+ name = tool.tool.get("label", os.path.basename(tool.tool["id"]))
+
upload_dependencies(arvRunner, name, document_loader,
packed, uri, False)
+ # TODO nowhere for submit_runner_ram to go.
+
body = {
"workflow": {
- "owner_uuid": project_uuid,
- "name": tool.tool.get("label", name),
+ "name": name,
"description": tool.tool.get("doc", ""),
- "definition":yaml.safe_dump(packed)
+ "definition":yaml.round_trip_dump(packed)
}}
+ if project_uuid:
+ body["workflow"]["owner_uuid"] = project_uuid
- if update_uuid:
- return arvRunner.api.workflows().update(uuid=update_uuid, body=body).execute(num_retries=arvRunner.num_retries)["uuid"]
+ if uuid:
+ call = arvRunner.api.workflows().update(uuid=uuid, body=body)
else:
- return arvRunner.api.workflows().create(body=body).execute(num_retries=arvRunner.num_retries)["uuid"]
+ call = arvRunner.api.workflows().create(body=body)
+ return call.execute(num_retries=arvRunner.num_retries)["uuid"]
class ArvadosWorkflow(Workflow):
"""Wrap cwltool Workflow to override selected methods."""
kwargs["work_api"] = self.work_api
req, _ = self.get_requirement("http://arvados.org/cwl#RunInSingleContainer")
if req:
+ with SourceLine(self.tool, None, WorkflowException):
+ if "id" not in self.tool:
+ raise WorkflowException("%s object must have 'id'" % (self.tool["class"]))
document_loader, workflowobj, uri = (self.doc_loader, self.doc_loader.fetch(self.tool["id"]), self.tool["id"])
with Perf(metrics, "subworkflow upload_deps"):
joborder_keepmount = copy.deepcopy(joborder)
def keepmount(obj):
- if "location" not in obj:
- raise WorkflowException("%s object is missing required 'location' field: %s" % (obj["class"], obj))
- if obj["location"].startswith("keep:"):
- obj["location"] = "/keep/" + obj["location"][5:]
- if "listing" in obj:
- del obj["listing"]
- elif obj["location"].startswith("_:"):
- del obj["location"]
- else:
- raise WorkflowException("Location is not a keep reference or a literal: '%s'" % obj["location"])
+ with SourceLine(obj, None, WorkflowException):
+ if "location" not in obj:
+ raise WorkflowException("%s object is missing required 'location' field: %s" % (obj["class"], obj))
+ with SourceLine(obj, "location", WorkflowException):
+ if obj["location"].startswith("keep:"):
+ obj["location"] = "/keep/" + obj["location"][5:]
+ if "listing" in obj:
+ del obj["listing"]
+ elif obj["location"].startswith("_:"):
+ del obj["location"]
+ else:
+ raise WorkflowException("Location is not a keep reference or a literal: '%s'" % obj["location"])
adjustFileObjs(joborder_keepmount, keepmount)
adjustDirObjs(joborder_keepmount, keepmount)
adjustFileObjs(packed, keepmount)
adjustDirObjs(packed, keepmount)
- wf_runner = {
+ wf_runner = cmap({
"class": "CommandLineTool",
"baseCommand": "cwltool",
"inputs": self.tool["inputs"],
"class": "InitialWorkDirRequirement",
"listing": [{
"entryname": "workflow.cwl",
- "entry": yaml.safe_dump(packed).replace("\\", "\\\\").replace('$(', '\$(').replace('${', '\${')
+ "entry": yaml.round_trip_dump(packed).replace("\\", "\\\\").replace('$(', '\$(').replace('${', '\${')
}, {
"entryname": "cwl.input.yml",
- "entry": yaml.safe_dump(joborder_keepmount).replace("\\", "\\\\").replace('$(', '\$(').replace('${', '\${')
+ "entry": yaml.round_trip_dump(joborder_keepmount).replace("\\", "\\\\").replace('$(', '\$(').replace('${', '\${')
}]
}],
"hints": workflowobj["hints"],
"arguments": ["--no-container", "--move-outputs", "--preserve-entire-environment", "workflow.cwl#main", "cwl.input.yml"]
- }
+ })
kwargs["loader"] = self.doc_loader
kwargs["avsc_names"] = self.doc_schema
return ArvadosCommandTool(self.arvrunner, wf_runner, **kwargs).job(joborder, output_callback, **kwargs)
from cwltool.load_tool import load_tool
from cwltool.errors import WorkflowException
+from .fsaccess import CollectionFetcher
+
logger = logging.getLogger('arvados.cwl-runner')
def run():
+ # Timestamps are added by crunch-job, so don't print redundant timestamps.
+ arvados.log_handler.setFormatter(logging.Formatter('%(name)s %(levelname)s: %(message)s'))
+
# Print package versions
logger.info(arvados_cwl.versionstring())
runner = None
try:
job_order_object = arvados.current_job()['script_parameters']
+ toolpath = "file://%s/%s" % (os.environ['TASK_KEEPMOUNT'], job_order_object.pop("cwl:tool"))
pdh_path = re.compile(r'^[0-9a-f]{32}\+\d+(/.+)?$')
def keeppathObj(v):
v["location"] = keeppath(v["location"])
- job_order_object["cwl:tool"] = "file://%s/%s" % (os.environ['TASK_KEEPMOUNT'], job_order_object["cwl:tool"])
-
for k,v in job_order_object.items():
if isinstance(v, basestring) and arvados.util.keep_locator_pattern.match(v):
job_order_object[k] = {
adjustDirObjs(job_order_object, functools.partial(getListing, arvados_cwl.fsaccess.CollectionFsAccess("", api_client=api)))
output_name = None
+ output_tags = None
enable_reuse = True
+ on_error = "continue"
if "arv:output_name" in job_order_object:
output_name = job_order_object["arv:output_name"]
del job_order_object["arv:output_name"]
+ if "arv:output_tags" in job_order_object:
+ output_tags = job_order_object["arv:output_tags"]
+ del job_order_object["arv:output_tags"]
+
if "arv:enable_reuse" in job_order_object:
enable_reuse = job_order_object["arv:enable_reuse"]
del job_order_object["arv:enable_reuse"]
+ if "arv:on_error" in job_order_object:
+ on_error = job_order_object["arv:on_error"]
+ del job_order_object["arv:on_error"]
+
runner = arvados_cwl.ArvCwlRunner(api_client=arvados.api('v1', model=OrderedJsonModel()),
- output_name=output_name)
+ output_name=output_name, output_tags=output_tags)
- t = load_tool(job_order_object, runner.arv_make_tool)
+ t = load_tool(toolpath, runner.arv_make_tool,
+ fetcher_constructor=functools.partial(CollectionFetcher,
+ api_client=api,
+ keep_client=arvados.keep.KeepClient(api_client=api, num_retries=4)))
args = argparse.Namespace()
args.project_uuid = arvados.current_job()["owner_uuid"]
args.enable_reuse = enable_reuse
+ args.on_error = on_error
args.submit = False
- args.debug = True
+ args.debug = False
args.quiet = False
args.ignore_docker_for_reuse = False
args.basedir = os.getcwd()
+ args.name = None
args.cwl_runner_job={"uuid": arvados.current_job()["uuid"], "state": arvados.current_job()["state"]}
- outputObj = runner.arv_executor(t, job_order_object, **vars(args))
+ runner.arv_executor(t, job_order_object, **vars(args))
except Exception as e:
if isinstance(e, WorkflowException):
logging.info("Workflow error %s", e)
+import re
from cwltool.errors import WorkflowException
+from collections import deque
def done(self, record, tmpdir, outdir, keepdir):
colname = "Output %s of %s" % (record["output"][0:7], self.name)
if not collections["items"]:
raise WorkflowException(
- "Job output '%s' cannot be found on API server" % (
- record["output"]))
+ "[job %s] output '%s' cannot be found on API server" % (
+ self.name, record["output"]))
# Create new collection in the parent project
# with the output contents.
}, ensure_unique_name=True).execute(
num_retries=self.arvrunner.num_retries)
+ return done_outputs(self, record, tmpdir, outdir, keepdir)
+
+def done_outputs(self, record, tmpdir, outdir, keepdir):
self.builder.outdir = outdir
self.builder.pathmapper.keepdir = keepdir
return self.collect_outputs("keep:" + record["output"])
+
+crunchstat_re = re.compile(r"^\d{4}-\d\d-\d\d_\d\d:\d\d:\d\d [a-z0-9]{5}-8i9sb-[a-z0-9]{15} \d+ \d+ stderr crunchstat:")
+timestamp_re = re.compile(r"^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+Z) (.*)")
+
+def logtail(logcollection, logger, header, maxlen=25):
+ logtail = deque([], maxlen*len(logcollection))
+ containersapi = ("crunch-run.txt" in logcollection)
+
+ for log in logcollection.keys():
+ if not containersapi or log in ("crunch-run.txt", "stdout.txt", "stderr.txt"):
+ logname = log[:-4]
+ with logcollection.open(log) as f:
+ for l in f:
+ if containersapi:
+ g = timestamp_re.match(l)
+ logtail.append("%s %s %s" % (g.group(1), logname, g.group(2)))
+ elif not crunchstat_re.match(l):
+ logtail.append(l)
+ if len(logcollection) > 1:
+ logtail = sorted(logtail)[-maxlen:]
+ logtxt = "\n ".join(l.strip() for l in logtail)
+ logger.info(header)
+ logger.info("\n %s", logtxt)
import fnmatch
import os
import errno
+import urlparse
+import re
+
+import ruamel.yaml as yaml
import cwltool.stdfsaccess
from cwltool.pathmapper import abspath
+import cwltool.resolver
import arvados.util
import arvados.collection
import arvados.arvfile
+from schema_salad.ref_resolver import DefaultFetcher
+
class CollectionFsAccess(cwltool.stdfsaccess.StdFsAccess):
"""Implement the cwltool FsAccess interface for Arvados Collections."""
return path
else:
return os.path.realpath(path)
+
+class CollectionFetcher(DefaultFetcher):
+ def __init__(self, cache, session, api_client=None, keep_client=None):
+ super(CollectionFetcher, self).__init__(cache, session)
+ self.api_client = api_client
+ self.fsaccess = CollectionFsAccess("", api_client=api_client, keep_client=keep_client)
+
+ def fetch_text(self, url):
+ if url.startswith("keep:"):
+ with self.fsaccess.open(url, "r") as f:
+ return f.read()
+ if url.startswith("arvwf:"):
+ return self.api_client.workflows().get(uuid=url[6:]).execute()["definition"]
+ return super(CollectionFetcher, self).fetch_text(url)
+
+ def check_exists(self, url):
+ if url.startswith("keep:"):
+ return self.fsaccess.exists(url)
+ if url.startswith("arvwf:"):
+ if self.fetch_text(url):
+ return True
+ return super(CollectionFetcher, self).check_exists(url)
+
+ def urljoin(self, base_url, url):
+ if not url:
+ return base_url
+
+ urlsp = urlparse.urlsplit(url)
+ if urlsp.scheme or not base_url:
+ return url
+
+ basesp = urlparse.urlsplit(base_url)
+ if basesp.scheme in ("keep", "arvwf"):
+ if not basesp.path:
+ raise IOError(errno.EINVAL, "Invalid Keep locator", base_url)
+
+ baseparts = basesp.path.split("/")
+ urlparts = urlsp.path.split("/") if urlsp.path else []
+
+ pdh = baseparts.pop(0)
+
+ if basesp.scheme == "keep" and not arvados.util.keep_locator_pattern.match(pdh):
+ raise IOError(errno.EINVAL, "Invalid Keep locator", base_url)
+
+ if urlsp.path.startswith("/"):
+ baseparts = []
+ urlparts.pop(0)
+
+ if baseparts and urlsp.path:
+ baseparts.pop()
+
+ path = "/".join([pdh] + baseparts + urlparts)
+ return urlparse.urlunsplit((basesp.scheme, "", path, "", urlsp.fragment))
+
+ return super(CollectionFetcher, self).urljoin(base_url, url)
+
+workflow_uuid_pattern = re.compile(r'[a-z0-9]{5}-7fd4e-[a-z0-9]{15}')
+pipeline_template_uuid_pattern = re.compile(r'[a-z0-9]{5}-p5p6p-[a-z0-9]{15}')
+
+def collectionResolver(api_client, document_loader, uri):
+ if workflow_uuid_pattern.match(uri):
+ return "arvwf:%s#main" % (uri)
+
+ if pipeline_template_uuid_pattern.match(uri):
+ pt = api_client.pipeline_templates().get(uuid=uri).execute()
+ return "keep:" + pt["components"].values()[0]["script_parameters"]["cwl:tool"]
+
+ p = uri.split("/")
+ if arvados.util.keep_locator_pattern.match(p[0]):
+ return "keep:%s" % (uri)
+
+ if arvados.util.collection_uuid_pattern.match(p[0]):
+ return "keep:%s%s" % (api_client.collections().
+ get(uuid=p[0]).execute()["portable_data_hash"],
+ uri[len(p[0]):])
+
+ return cwltool.resolver.tool_resolver(document_loader, uri)
import arvados.commands.run
import arvados.collection
+from schema_salad.sourceline import SourceLine
+
from cwltool.pathmapper import PathMapper, MapperEnt, abspath, adjustFileObjs, adjustDirObjs
from cwltool.workflow import WorkflowException
# mount.
ab = abspath(src, self.input_basedir)
st = arvados.commands.run.statfile("", ab, fnPattern="keep:%s/%s")
- if isinstance(st, arvados.commands.run.UploadFile):
- uploadfiles.add((src, ab, st))
- elif isinstance(st, arvados.commands.run.ArvFile):
- self._pathmap[src] = MapperEnt(st.fn, self.collection_pattern % st.fn[5:], "File")
- elif src.startswith("_:"):
- if "contents" in srcobj:
- pass
+ with SourceLine(srcobj, "location", WorkflowException):
+ if isinstance(st, arvados.commands.run.UploadFile):
+ uploadfiles.add((src, ab, st))
+ elif isinstance(st, arvados.commands.run.ArvFile):
+ self._pathmap[src] = MapperEnt(st.fn, self.collection_pattern % st.fn[5:], "File")
+ elif src.startswith("_:"):
+ if "contents" in srcobj:
+ pass
+ else:
+ raise WorkflowException("File literal '%s' is missing contents" % src)
+ elif src.startswith("arvwf:"):
+ self._pathmap[src] = MapperEnt(src, src, "File")
else:
- raise WorkflowException("File literal '%s' is missing contents" % src)
- else:
- raise WorkflowException("Input file path '%s' is invalid" % st)
+ raise WorkflowException("Input file path '%s' is invalid" % st)
if "secondaryFiles" in srcobj:
for l in srcobj["secondaryFiles"]:
self.visit(l, uploadfiles)
with c.open(path + "/" + obj["basename"], "w") as f:
f.write(obj["contents"].encode("utf-8"))
else:
- raise WorkflowException("Don't know what to do with '%s'" % obj["location"])
+ raise SourceLine(obj, "location", WorkflowException).makeError("Don't know what to do with '%s'" % obj["location"])
def setup(self, referenced_files, basedir):
# type: (List[Any], unicode) -> None
import re
from cStringIO import StringIO
+from schema_salad.sourceline import SourceLine
+
import cwltool.draft2tool
from cwltool.draft2tool import CommandLineTool
import cwltool.workflow
from .arvdocker import arv_docker_get_image
from .pathmapper import ArvPathMapper
from ._version import __version__
+from . import done
logger = logging.getLogger('arvados.cwl-runner')
loaded = set()
def loadref(b, u):
- joined = urlparse.urljoin(b, u)
+ joined = document_loader.fetcher.urljoin(b, u)
defrg, _ = urlparse.urldefrag(joined)
if defrg not in loaded:
loaded.add(defrg)
sc = scandeps(uri, scanobj,
loadref_fields,
set(("$include", "$schemas", "location")),
- loadref)
+ loadref, urljoin=document_loader.fetcher.urljoin)
normalizeFilesDirs(sc)
if docker_req:
if docker_req.get("dockerOutputDirectory"):
# TODO: can be supported by containers API, but not jobs API.
- raise UnsupportedRequirement("Option 'dockerOutputDirectory' of DockerRequirement not supported.")
+ raise SourceLine(docker_req, "dockerOutputDirectory", UnsupportedRequirement).makeError(
+ "Option 'dockerOutputDirectory' of DockerRequirement not supported.")
arv_docker_get_image(arvrunner.api, docker_req, True, arvrunner.project_uuid)
elif isinstance(tool, cwltool.workflow.Workflow):
for s in tool.steps:
return img
class Runner(object):
- def __init__(self, runner, tool, job_order, enable_reuse, output_name):
+ def __init__(self, runner, tool, job_order, enable_reuse,
+ output_name, output_tags, submit_runner_ram=0,
+ name=None, on_error=None):
self.arvrunner = runner
self.tool = tool
self.job_order = job_order
self.uuid = None
self.final_output = None
self.output_name = output_name
+ self.output_tags = output_tags
+ self.name = name
+ self.on_error = on_error
+
+ if submit_runner_ram:
+ self.submit_runner_ram = submit_runner_ram
+ else:
+ self.submit_runner_ram = 1024
+
+ if self.submit_runner_ram <= 0:
+ raise Exception("Value of --submit-runner-ram must be greater than zero")
def update_pipeline_component(self, record):
pass
def arvados_job_spec(self, *args, **kwargs):
- self.name = os.path.basename(self.tool.tool["id"])
+ if self.name is None:
+ self.name = self.tool.tool.get("label") or os.path.basename(self.tool.tool["id"])
+
+ # Need to filter this out, gets added by cwltool when providing
+ # parameters on the command line.
+ if "job_order" in self.job_order:
+ del self.job_order["job_order"]
+
workflowmapper = upload_instance(self.arvrunner, self.name, self.tool, self.job_order)
adjustDirObjs(self.job_order, trim_listing)
return workflowmapper
def done(self, record):
- if record["state"] == "Complete":
- if record.get("exit_code") is not None:
- if record["exit_code"] == 33:
- processStatus = "UnsupportedRequirement"
- elif record["exit_code"] == 0:
- processStatus = "success"
+ try:
+ if record["state"] == "Complete":
+ if record.get("exit_code") is not None:
+ if record["exit_code"] == 33:
+ processStatus = "UnsupportedRequirement"
+ elif record["exit_code"] == 0:
+ processStatus = "success"
+ else:
+ processStatus = "permanentFail"
else:
- processStatus = "permanentFail"
+ processStatus = "success"
else:
- processStatus = "success"
- else:
- processStatus = "permanentFail"
+ processStatus = "permanentFail"
- outputs = None
- try:
- try:
- self.final_output = record["output"]
- outc = arvados.collection.CollectionReader(self.final_output,
+ outputs = {}
+
+ if processStatus == "permanentFail":
+ logc = arvados.collection.CollectionReader(record["log"],
api_client=self.arvrunner.api,
keep_client=self.arvrunner.keep_client,
num_retries=self.arvrunner.num_retries)
+ done.logtail(logc, logger, "%s error log:" % self.arvrunner.label(self), maxlen=40)
+
+ self.final_output = record["output"]
+ outc = arvados.collection.CollectionReader(self.final_output,
+ api_client=self.arvrunner.api,
+ keep_client=self.arvrunner.keep_client,
+ num_retries=self.arvrunner.num_retries)
+ if "cwl.output.json" in outc:
with outc.open("cwl.output.json") as f:
- outputs = json.load(f)
- def keepify(fileobj):
- path = fileobj["location"]
- if not path.startswith("keep:"):
- fileobj["location"] = "keep:%s/%s" % (record["output"], path)
- adjustFileObjs(outputs, keepify)
- adjustDirObjs(outputs, keepify)
- except Exception as e:
- logger.error("While getting final output object: %s", e)
+ if f.size() > 0:
+ outputs = json.load(f)
+ def keepify(fileobj):
+ path = fileobj["location"]
+ if not path.startswith("keep:"):
+ fileobj["location"] = "keep:%s/%s" % (record["output"], path)
+ adjustFileObjs(outputs, keepify)
+ adjustDirObjs(outputs, keepify)
+ except Exception as e:
+ logger.exception("[%s] While getting final output object: %s", self.name, e)
+ self.arvrunner.output_callback({}, "permanentFail")
+ else:
self.arvrunner.output_callback(outputs, processStatus)
finally:
- del self.arvrunner.processes[record["uuid"]]
+ if record["uuid"] in self.arvrunner.processes:
+ del self.arvrunner.processes[record["uuid"]]
'bin/cwl-runner',
'bin/arvados-cwl-runner'
],
- # Make sure to update arvados/build/run-build-packages.sh as well
- # when updating the cwltool version pin.
+ # Note that arvados/build/run-build-packages.sh looks at this
+ # file to determine what version of cwltool and schema-salad to build.
install_requires=[
- 'cwltool==1.0.20161107145355',
- 'arvados-python-client>=0.1.20160826210445'
+ 'cwltool==1.0.20170112185927',
+ 'schema-salad==2.2.20170111180227',
+ 'ruamel.yaml==0.13.7',
+ 'arvados-python-client>=0.1.20170112173420',
+ 'setuptools'
],
data_files=[
('share/doc/arvados-cwl-runner', ['LICENSE-2.0.txt', 'README.rst']),
import functools
import cwltool.process
from schema_salad.ref_resolver import Loader
+from schema_salad.sourceline import cmap
-from schema_salad.ref_resolver import Loader
+from .matcher import JsonDiffMatcher
if not os.getenv('ARVADOS_DEBUG'):
logging.getLogger('arvados.cwl-runner').setLevel(logging.WARN)
document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
- tool = {
+ tool = cmap({
"inputs": [],
"outputs": [],
"baseCommand": "ls",
"arguments": [{"valueFrom": "$(runtime.outdir)"}]
- }
+ })
make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers", avsc_names=avsc_names,
basedir="", make_fs_access=make_fs_access, loader=Loader({}))
make_fs_access=make_fs_access, tmpdir="/tmp"):
j.run(enable_reuse=enable_reuse)
runner.api.container_requests().create.assert_called_with(
- body={
+ body=JsonDiffMatcher({
'environment': {
'HOME': '/var/spool/cwl',
'TMPDIR': '/tmp'
'output_path': '/var/spool/cwl',
'container_image': '99999999999999999999999999999993+99',
'command': ['ls', '/var/spool/cwl'],
- 'cwd': '/var/spool/cwl'
- })
+ 'cwd': '/var/spool/cwl',
+ 'scheduling_parameters': {},
+ 'properties': {},
+ }))
# The test passes some fields in builder.resources
# For the remaining fields, the defaults will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
runner.api.collections().get().execute.return_value = {
"portable_data_hash": "99999999999999999999999999999993+99"}
- tool = {
+ tool = cmap({
"inputs": [],
"outputs": [],
"hints": [{
"partition": "blurb"
}],
"baseCommand": "ls"
- }
+ })
make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers",
avsc_names=avsc_names, make_fs_access=make_fs_access,
make_fs_access=make_fs_access, tmpdir="/tmp"):
j.run()
- runner.api.container_requests().create.assert_called_with(
- body={
+ call_args, call_kwargs = runner.api.container_requests().create.call_args
+
+ call_body_expected = {
'environment': {
'HOME': '/var/spool/cwl',
'TMPDIR': '/tmp'
'vcpus': 3,
'ram': 3145728000,
'keep_cache_ram': 512,
- 'API': True,
- 'partition': ['blurb']
+ 'API': True
},
'use_existing': True,
'priority': 1,
'output_path': '/var/spool/cwl',
'container_image': '99999999999999999999999999999993+99',
'command': ['ls'],
- 'cwd': '/var/spool/cwl'
- })
+ 'cwd': '/var/spool/cwl',
+ 'scheduling_parameters': {
+ 'partitions': ['blurb']
+ },
+ 'properties': {}
+ }
+
+ call_body = call_kwargs.get('body', None)
+ self.assertNotEqual(None, call_body)
+ for key in call_body:
+ self.assertEqual(call_body_expected.get(key), call_body.get(key))
@mock.patch("arvados.collection.Collection")
def test_done(self, col):
runner.num_retries = 0
runner.ignore_docker_for_reuse = False
- col().open.return_value = []
- api.collections().list().execute.side_effect = ({"items": []},
- {"items": [{"manifest_text": "XYZ"}]})
-
- arvjob = arvados_cwl.ArvadosContainer(runner)
- arvjob.name = "testjob"
- arvjob.builder = mock.MagicMock()
- arvjob.output_callback = mock.MagicMock()
- arvjob.collect_outputs = mock.MagicMock()
- arvjob.successCodes = [0]
- arvjob.outdir = "/var/spool/cwl"
-
- arvjob.done({
- "state": "Complete",
- "output": "99999999999999999999999999999993+99",
- "log": "99999999999999999999999999999994+99",
- "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
- "exit_code": 0
- })
-
- api.collections().list.assert_has_calls([
- mock.call(),
- mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
- ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
- ['name', '=', 'Output 9999999 of testjob']]),
- mock.call().execute(num_retries=0),
- mock.call(limit=1, filters=[['portable_data_hash', '=', '99999999999999999999999999999993+99']],
- select=['manifest_text']),
- mock.call().execute(num_retries=0)])
-
- api.collections().create.assert_called_with(
- ensure_unique_name=True,
- body={'portable_data_hash': '99999999999999999999999999999993+99',
- 'manifest_text': 'XYZ',
- 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
- 'name': 'Output 9999999 of testjob'})
-
- @mock.patch("arvados.collection.Collection")
- def test_done_use_existing_collection(self, col):
- api = mock.MagicMock()
-
- runner = mock.MagicMock()
- runner.api = api
- runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
- runner.num_retries = 0
+ runner.api.containers().get().execute.return_value = {"state":"Complete",
+ "output": "abc+123",
+ "exit_code": 0}
col().open.return_value = []
- api.collections().list().execute.side_effect = ({"items": [{"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2"}]},)
arvjob = arvados_cwl.ArvadosContainer(runner)
arvjob.name = "testjob"
arvjob.successCodes = [0]
arvjob.outdir = "/var/spool/cwl"
+ arvjob.collect_outputs.return_value = {"out": "stuff"}
+
arvjob.done({
- "state": "Complete",
- "output": "99999999999999999999999999999993+99",
- "log": "99999999999999999999999999999994+99",
- "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
- "exit_code": 0
+ "state": "Final",
+ "log_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz1",
+ "output_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2",
+ "uuid": "zzzzz-xvhdp-zzzzzzzzzzzzzzz",
+ "container_uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
})
- api.collections().list.assert_has_calls([
- mock.call(),
- mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
- ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
- ['name', '=', 'Output 9999999 of testjob']]),
- mock.call().execute(num_retries=0)])
-
self.assertFalse(api.collections().create.called)
+
+ arvjob.collect_outputs.assert_called_with("keep:abc+123")
+ arvjob.output_callback.assert_called_with({"out": "stuff"}, "success")
import arvados_cwl
import cwltool.process
from schema_salad.ref_resolver import Loader
+from schema_salad.sourceline import cmap
from .mock_discovery import get_rootDesc
+from .matcher import JsonDiffMatcher
if not os.getenv('ARVADOS_DEBUG'):
logging.getLogger('arvados.cwl-runner').setLevel(logging.WARN)
list_images_in_arv.return_value = [["zzzzz-4zz18-zzzzzzzzzzzzzzz"]]
runner.api.collections().get().execute.return_vaulue = {"portable_data_hash": "99999999999999999999999999999993+99"}
- tool = {
+ tool = cmap({
"inputs": [],
"outputs": [],
"baseCommand": "ls",
"arguments": [{"valueFrom": "$(runtime.outdir)"}]
- }
+ })
make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="jobs", avsc_names=avsc_names,
basedir="", make_fs_access=make_fs_access, loader=Loader({}))
for j in arvtool.job({}, mock.MagicMock(), basedir="", make_fs_access=make_fs_access):
j.run(enable_reuse=enable_reuse)
runner.api.jobs().create.assert_called_with(
- body={
+ body=JsonDiffMatcher({
'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
'runtime_constraints': {},
'script_parameters': {
}],
},
'script_version': 'master',
- 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
+ 'minimum_script_version': 'a3f2cb186e437bfce0031b024b2157b73ed2717d',
'repository': 'arvados',
'script': 'crunchrunner',
'runtime_constraints': {
'min_ram_mb_per_node': 1024,
'min_scratch_mb_per_node': 2048 # tmpdirSize + outdirSize
}
- },
+ }),
find_or_create=enable_reuse,
filters=[['repository', '=', 'arvados'],
['script', '=', 'crunchrunner'],
- ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
+ ['script_version', 'in git', 'a3f2cb186e437bfce0031b024b2157b73ed2717d'],
['docker_image_locator', 'in docker', 'arvados/jobs:'+arvados_cwl.__version__]]
)
for j in arvtool.job({}, mock.MagicMock(), basedir="", make_fs_access=make_fs_access):
j.run()
runner.api.jobs().create.assert_called_with(
- body={
+ body=JsonDiffMatcher({
'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
'runtime_constraints': {},
'script_parameters': {
}]
},
'script_version': 'master',
- 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
+ 'minimum_script_version': 'a3f2cb186e437bfce0031b024b2157b73ed2717d',
'repository': 'arvados',
'script': 'crunchrunner',
'runtime_constraints': {
'min_scratch_mb_per_node': 5024, # tmpdirSize + outdirSize
'keep_cache_mb_per_task': 512
}
- },
+ }),
find_or_create=True,
filters=[['repository', '=', 'arvados'],
['script', '=', 'crunchrunner'],
- ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
+ ['script_version', 'in git', 'a3f2cb186e437bfce0031b024b2157b73ed2717d'],
['docker_image_locator', 'in docker', 'arvados/jobs:'+arvados_cwl.__version__]])
@mock.patch("arvados.collection.CollectionReader")
arvjob.builder = mock.MagicMock()
arvjob.output_callback = mock.MagicMock()
arvjob.collect_outputs = mock.MagicMock()
+ arvjob.collect_outputs.return_value = {"out": "stuff"}
arvjob.done({
"state": "Complete",
'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
'name': 'Output 9999999 of testjob'})
+ arvjob.output_callback.assert_called_with({"out": "stuff"}, "success")
+
@mock.patch("arvados.collection.CollectionReader")
def test_done_use_existing_collection(self, reader):
api = mock.MagicMock()
arvjob.builder = mock.MagicMock()
arvjob.output_callback = mock.MagicMock()
arvjob.collect_outputs = mock.MagicMock()
+ arvjob.collect_outputs.return_value = {"out": "stuff"}
arvjob.done({
"state": "Complete",
self.assertFalse(api.collections().create.called)
+ arvjob.output_callback.assert_called_with({"out": "stuff"}, "success")
+
class TestWorkflow(unittest.TestCase):
# The test passes no builder.resources
subwf = f.read()
runner.api.jobs().create.assert_called_with(
- body={
- 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
+ body=JsonDiffMatcher({
+ 'minimum_script_version': 'a3f2cb186e437bfce0031b024b2157b73ed2717d',
'repository': 'arvados',
'script_version': 'master',
'script': 'crunchrunner',
'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
'min_ram_mb_per_node': 1024
},
- 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'},
+ 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'}),
filters=[['repository', '=', 'arvados'],
['script', '=', 'crunchrunner'],
- ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
+ ['script_version', 'in git', 'a3f2cb186e437bfce0031b024b2157b73ed2717d'],
['docker_image_locator', 'in docker', 'arvados/jobs:'+arvados_cwl.__version__]],
find_or_create=True)
mockcollection().open().__enter__().write.assert_has_calls([mock.call(subwf)])
- mockcollection().open().__enter__().write.assert_has_calls([mock.call('{sleeptime: 5}')])
+ mockcollection().open().__enter__().write.assert_has_calls([mock.call('sleeptime: 5')])
def test_default_work_api(self):
arvados_cwl.add_arv_hints()
readermock = mock.MagicMock()
reader.return_value = readermock
+ final_uuid = final.manifest_locator()
+ num_retries = runner.num_retries
+
cwlout = StringIO.StringIO()
openmock = mock.MagicMock()
final.open.return_value = openmock
openmock.__enter__.return_value = cwlout
- _, runner.final_output_collection = runner.make_output_collection("Test output", {
+ _, runner.final_output_collection = runner.make_output_collection("Test output", "tag0,tag1,tag2", {
"foo": {
"class": "File",
"location": "keep:99999999999999999999999999999991+99/foo.txt",
}""", cwlout.getvalue())
self.assertIs(final, runner.final_output_collection)
+ self.assertIs(final_uuid, runner.final_output_collection.manifest_locator())
+ self.api.links().create.assert_has_calls([mock.call(body={"head_uuid": final_uuid, "link_class": "tag", "name": "tag0"}), mock.call().execute(num_retries=num_retries)])
+ self.api.links().create.assert_has_calls([mock.call(body={"head_uuid": final_uuid, "link_class": "tag", "name": "tag1"}), mock.call().execute(num_retries=num_retries)])
+ self.api.links().create.assert_has_calls([mock.call(body={"head_uuid": final_uuid, "link_class": "tag", "name": "tag2"}), mock.call().execute(num_retries=num_retries)])
}
stubs.expect_job_spec = {
'runtime_constraints': {
- 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__
+ 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
+ 'min_ram_mb_per_node': 1024
},
'script_parameters': {
'x': {
'99999999999999999999999999999991+99/wf/submit_wf.cwl'
},
'repository': 'arvados',
- 'script_version': arvados_cwl.__version__,
+ 'script_version': 'master',
+ 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
'script': 'cwl-runner'
}
stubs.pipeline_component = stubs.expect_job_spec.copy()
stubs.expect_pipeline_instance = {
'name': 'submit_wf.cwl',
'state': 'RunningOnServer',
+ 'owner_uuid': None,
"components": {
"cwl-runner": {
- 'runtime_constraints': {'docker_image': 'arvados/jobs:'+arvados_cwl.__version__},
+ 'runtime_constraints': {'docker_image': 'arvados/jobs:'+arvados_cwl.__version__, 'min_ram_mb_per_node': 1024},
'script_parameters': {
'y': {"value": {'basename': '99999999999999999999999999999998+99', 'location': 'keep:99999999999999999999999999999998+99', 'class': 'Directory'}},
'x': {"value": {'basename': 'blorp.txt', 'class': 'File', 'location': 'keep:99999999999999999999999999999994+99/blorp.txt'}},
{'basename': 'renamed.txt', 'class': 'File', 'location': 'keep:99999999999999999999999999999998+99/file1.txt'}
]}},
'cwl:tool': '99999999999999999999999999999991+99/wf/submit_wf.cwl',
- 'arv:enable_reuse': True
+ 'arv:enable_reuse': True,
+ 'arv:on_error': 'continue'
},
'repository': 'arvados',
- 'script_version': arvados_cwl.__version__,
+ 'script_version': 'master',
+ 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
'script': 'cwl-runner',
'job': {'state': 'Queued', 'uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'}
}
'path': '/var/spool/cwl/cwl.output.json',
'kind': 'file'
},
- '/var/lib/cwl/job/cwl.input.json': {
- 'portable_data_hash': 'd20d7cddd1984f105dd3702c7f125afb+60/cwl.input.json',
- 'kind': 'collection'
+ '/var/lib/cwl/cwl.input.json': {
+ 'kind': 'json',
+ 'content': {
+ 'y': {'basename': '99999999999999999999999999999998+99', 'location': 'keep:99999999999999999999999999999998+99', 'class': 'Directory'},
+ 'x': {'basename': u'blorp.txt', 'class': 'File', 'location': u'keep:99999999999999999999999999999994+99/blorp.txt'},
+ 'z': {'basename': 'anonymous', 'class': 'Directory', 'listing': [
+ {'basename': 'renamed.txt', 'class': 'File', 'location': 'keep:99999999999999999999999999999998+99/file1.txt'}
+ ]}
+ },
+ 'kind': 'json'
}
},
'state': 'Committed',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
- 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--enable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json'],
+ 'owner_uuid': None,
+ 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ '--enable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/cwl.input.json'],
'name': 'submit_wf.cwl',
'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
'output_path': '/var/spool/cwl',
'runtime_constraints': {
'API': True,
'vcpus': 1,
- 'ram': 268435456
- }
+ 'ram': 1024*1024*1024
+ },
+ "properties": {}
}
stubs.expect_workflow_uuid = "zzzzz-7fd4e-zzzzzzzzzzzzzzz"
stubs.api.workflows().create().execute.return_value = {
"uuid": stubs.expect_workflow_uuid,
}
+ def update_mock(**kwargs):
+ stubs.updated_uuid = kwargs.get('uuid')
+ return mock.DEFAULT
+ stubs.api.workflows().update.side_effect = update_mock
+ stubs.api.workflows().update().execute.side_effect = lambda **kwargs: {
+ "uuid": stubs.updated_uuid,
+ }
return func(self, stubs, *args, **kwargs)
return wrapped
'./tool d51232d96b6116d964a69bfb7e0c73bf+450 '
'0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
'cc2ffb940e60adf1b2b282c67587e43d+413 0:413:submit_wf.cwl\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
+ 'owner_uuid': None,
'name': 'submit_wf.cwl',
}, ensure_unique_name=True),
mock.call().execute(),
mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
'0:0:blub.txt 0:0:submit_tool.cwl\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
'replication_desired': None,
'name': 'New collection'
}, ensure_unique_name=True),
mock.call(body={
'manifest_text':
'. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
+ 'owner_uuid': None,
'name': '#',
}, ensure_unique_name=True),
mock.call().execute()])
expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
- expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
stubs.api.pipeline_instances().create.assert_called_with(
body=expect_pipeline)
self.assertEqual(capture_stdout.getvalue(),
stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:enable_reuse"] = {"value": False}
expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
- expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
+ stubs.api.pipeline_instances().create.assert_called_with(
+ body=JsonDiffMatcher(expect_pipeline))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_uuid + '\n')
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_on_error(self, stubs, tm):
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--on-error=stop",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:on_error"] = "stop"
+
+ expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
+ stubs.api.pipeline_instances().create.assert_called_with(
+ body=JsonDiffMatcher(expect_pipeline))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_uuid + '\n')
+
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_runner_ram(self, stubs, tm):
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--submit-runner-ram=2048",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.expect_pipeline_instance["components"]["cwl-runner"]["runtime_constraints"]["min_ram_mb_per_node"] = 2048
+
+ expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
+ stubs.api.pipeline_instances().create.assert_called_with(
+ body=JsonDiffMatcher(expect_pipeline))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_uuid + '\n')
+
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_invalid_runner_ram(self, stubs, tm):
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--submit-runner-ram=-2048",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 1)
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_output_name(self, stubs, tm):
+ output_name = "test_output_name"
+
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--output-name", output_name,
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:output_name"] = output_name
+
+ expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
+ stubs.api.pipeline_instances().create.assert_called_with(
+ body=JsonDiffMatcher(expect_pipeline))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_uuid + '\n')
+
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_pipeline_name(self, stubs, tm):
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--name=hello job 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.expect_pipeline_instance["name"] = "hello job 123"
+
+ expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
stubs.api.pipeline_instances().create.assert_called_with(
body=expect_pipeline)
self.assertEqual(capture_stdout.getvalue(),
stubs.expect_pipeline_uuid + '\n')
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_output_tags(self, stubs, tm):
+ output_tags = "tag0,tag1,tag2"
+
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--debug", "--output-tags", output_tags,
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:output_tags"] = output_tags
+
+ expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
+ stubs.api.pipeline_instances().create.assert_called_with(
+ body=JsonDiffMatcher(expect_pipeline))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_uuid + '\n')
+
@mock.patch("time.sleep")
@stubs
def test_submit_with_project_uuid(self, stubs, tm):
expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
expect_pipeline["owner_uuid"] = project_uuid
stubs.api.pipeline_instances().create.assert_called_with(
- body=expect_pipeline)
+ body=JsonDiffMatcher(expect_pipeline))
@stubs
def test_submit_container(self, stubs):
'./tool d51232d96b6116d964a69bfb7e0c73bf+450 '
'0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
'cc2ffb940e60adf1b2b282c67587e43d+413 0:413:submit_wf.cwl\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
+ 'owner_uuid': None,
'name': 'submit_wf.cwl',
}, ensure_unique_name=True),
mock.call().execute(),
mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
'0:0:blub.txt 0:0:submit_tool.cwl\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
'name': 'New collection',
'replication_desired': None,
}, ensure_unique_name=True),
mock.call(body={
'manifest_text':
'. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
- 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
+ 'owner_uuid': None,
'name': '#',
}, ensure_unique_name=True),
mock.call().execute()])
expect_container = copy.deepcopy(stubs.expect_container_spec)
- expect_container["owner_uuid"] = stubs.fake_user_uuid
stubs.api.container_requests().create.assert_called_with(
- body=expect_container)
+ body=JsonDiffMatcher(expect_container))
self.assertEqual(capture_stdout.getvalue(),
stubs.expect_container_request_uuid + '\n')
except:
logging.exception("")
- stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--disable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json']
+ stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ '--disable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/cwl.input.json']
+
+ expect_container = copy.deepcopy(stubs.expect_container_spec)
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+
+ @stubs
+ def test_submit_container_on_error(self, stubs):
+ capture_stdout = cStringIO.StringIO()
+ try:
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug", "--on-error=stop",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
+ self.assertEqual(exited, 0)
+ except:
+ logging.exception("")
+
+ stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ '--enable-reuse', '--on-error=stop',
+ '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/cwl.input.json']
+
+ expect_container = copy.deepcopy(stubs.expect_container_spec)
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+ @stubs
+ def test_submit_container_output_name(self, stubs):
+ output_name = "test_output_name"
+
+ capture_stdout = cStringIO.StringIO()
+ try:
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug", "--output-name", output_name,
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
+ self.assertEqual(exited, 0)
+ except:
+ logging.exception("")
+
+ stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ "--output-name="+output_name, '--enable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/cwl.input.json']
+ stubs.expect_container_spec["output_name"] = output_name
+
+ expect_container = copy.deepcopy(stubs.expect_container_spec)
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+ @stubs
+ def test_submit_container_output_tags(self, stubs):
+ output_tags = "tag0,tag1,tag2"
+
+ capture_stdout = cStringIO.StringIO()
+ try:
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug", "--output-tags", output_tags,
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
+ self.assertEqual(exited, 0)
+ except:
+ logging.exception("")
+
+ stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ "--output-tags="+output_tags, '--enable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/cwl.input.json']
+
+ expect_container = copy.deepcopy(stubs.expect_container_spec)
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+ @stubs
+ def test_submit_container_runner_ram(self, stubs):
+ capture_stdout = cStringIO.StringIO()
+ try:
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug", "--submit-runner-ram=2048",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
+ self.assertEqual(exited, 0)
+ except:
+ logging.exception("")
+
+ stubs.expect_container_spec["runtime_constraints"]["ram"] = 2048*1024*1024
+
+ expect_container = copy.deepcopy(stubs.expect_container_spec)
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+ @mock.patch("arvados.collection.CollectionReader")
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_file_keepref(self, stubs, tm, collectionReader):
+ capture_stdout = cStringIO.StringIO()
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug",
+ "tests/wf/submit_keepref_wf.cwl"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+
+ @mock.patch("arvados.collection.CollectionReader")
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_keepref(self, stubs, tm, reader):
+ capture_stdout = cStringIO.StringIO()
+
+ with open("tests/wf/expect_arvworkflow.cwl") as f:
+ reader().open().__enter__().read.return_value = f.read()
+
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug",
+ "keep:99999999999999999999999999999994+99/expect_arvworkflow.cwl#main", "-x", "XxX"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ expect_container = {
+ 'priority': 1,
+ 'mounts': {
+ '/var/spool/cwl': {
+ 'writable': True,
+ 'kind': 'collection'
+ },
+ 'stdout': {
+ 'path': '/var/spool/cwl/cwl.output.json',
+ 'kind': 'file'
+ },
+ '/var/lib/cwl/workflow': {
+ 'portable_data_hash': '99999999999999999999999999999994+99',
+ 'kind': 'collection'
+ },
+ '/var/lib/cwl/cwl.input.json': {
+ 'content': {
+ 'x': 'XxX'
+ },
+ 'kind': 'json'
+ }
+ }, 'state': 'Committed',
+ 'owner_uuid': None,
+ 'output_path': '/var/spool/cwl',
+ 'name': 'expect_arvworkflow.cwl#main',
+ 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
+ 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ '--enable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow/expect_arvworkflow.cwl#main', '/var/lib/cwl/cwl.input.json'],
+ 'cwd': '/var/spool/cwl',
+ 'runtime_constraints': {
+ 'API': True,
+ 'vcpus': 1,
+ 'ram': 1073741824
+ },
+ "properties": {}
+ }
+
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+ @mock.patch("time.sleep")
+ @stubs
+ def test_submit_arvworkflow(self, stubs, tm):
+ capture_stdout = cStringIO.StringIO()
+
+ with open("tests/wf/expect_arvworkflow.cwl") as f:
+ stubs.api.workflows().get().execute.return_value = {"definition": f.read(), "name": "a test workflow"}
+
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug",
+ "962eh-7fd4e-gkbzl62qqtfig37", "-x", "XxX"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ expect_container = {
+ 'priority': 1,
+ 'mounts': {
+ '/var/spool/cwl': {
+ 'writable': True,
+ 'kind': 'collection'
+ },
+ 'stdout': {
+ 'path': '/var/spool/cwl/cwl.output.json',
+ 'kind': 'file'
+ },
+ '/var/lib/cwl/workflow.json': {
+ 'kind': 'json',
+ 'json': {
+ 'cwlVersion': 'v1.0',
+ '$graph': [
+ {
+ 'inputs': [
+ {
+ 'inputBinding': {'position': 1},
+ 'type': 'string',
+ 'id': '#submit_tool.cwl/x'}
+ ],
+ 'requirements': [
+ {'dockerPull': 'debian:8', 'class': 'DockerRequirement'}
+ ],
+ 'id': '#submit_tool.cwl',
+ 'outputs': [],
+ 'baseCommand': 'cat',
+ 'class': 'CommandLineTool'
+ }, {
+ 'id': '#main',
+ 'inputs': [
+ {'type': 'string', 'id': '#main/x'}
+ ],
+ 'steps': [
+ {'in': [{'source': '#main/x', 'id': '#main/step1/x'}],
+ 'run': '#submit_tool.cwl',
+ 'id': '#main/step1',
+ 'out': []}
+ ],
+ 'class': 'Workflow',
+ 'outputs': []
+ }
+ ]
+ }
+ },
+ '/var/lib/cwl/cwl.input.json': {
+ 'content': {
+ 'x': 'XxX'
+ },
+ 'kind': 'json'
+ }
+ }, 'state': 'Committed',
+ 'owner_uuid': None,
+ 'output_path': '/var/spool/cwl',
+ 'name': 'a test workflow',
+ 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
+ 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps',
+ '--enable-reuse', '--on-error=continue',
+ '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'],
+ 'cwd': '/var/spool/cwl',
+ 'runtime_constraints': {
+ 'API': True,
+ 'vcpus': 1,
+ 'ram': 1073741824
+ },
+ "properties": {
+ "template_uuid": "962eh-7fd4e-gkbzl62qqtfig37"
+ }
+ }
+
+ stubs.api.container_requests().create.assert_called_with(
+ body=JsonDiffMatcher(expect_container))
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_container_request_uuid + '\n')
+
+
+ @stubs
+ def test_submit_container_name(self, stubs):
+ capture_stdout = cStringIO.StringIO()
+ try:
+ exited = arvados_cwl.main(
+ ["--submit", "--no-wait", "--api=containers", "--debug", "--name=hello container 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
+ self.assertEqual(exited, 0)
+ except:
+ logging.exception("")
+
+ stubs.expect_container_spec["name"] = "hello container 123"
expect_container = copy.deepcopy(stubs.expect_container_spec)
- expect_container["owner_uuid"] = stubs.fake_user_uuid
stubs.api.container_requests().create.assert_called_with(
body=expect_container)
self.assertEqual(capture_stdout.getvalue(),
stubs.expect_container_request_uuid + '\n')
+
@mock.patch("arvados.commands.keepdocker.find_one_image_hash")
@mock.patch("cwltool.docker.get_image")
@mock.patch("arvados.api")
self.assertEqual("arvados/jobs:"+arvados_cwl.__version__, arvados_cwl.runner.arvados_jobs_image(arvrunner))
class TestCreateTemplate(unittest.TestCase):
- @stubs
- def test_create(self, stubs):
- project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
-
- capture_stdout = cStringIO.StringIO()
+ existing_template_uuid = "zzzzz-d1hrv-validworkfloyml"
- exited = arvados_cwl.main(
- ["--create-template", "--debug",
- "--project-uuid", project_uuid,
- "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
- capture_stdout, sys.stderr, api_client=stubs.api)
- self.assertEqual(exited, 0)
-
- stubs.api.pipeline_instances().create.refute_called()
- stubs.api.jobs().create.refute_called()
-
- expect_component = copy.deepcopy(stubs.expect_job_spec)
+ def _adjust_script_params(self, expect_component):
expect_component['script_parameters']['x'] = {
'dataclass': 'File',
'required': True,
'required': True,
'type': 'Directory',
}
+
+ @stubs
+ def test_create(self, stubs):
+ project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
+
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--create-workflow", "--debug",
+ "--api=jobs",
+ "--project-uuid", project_uuid,
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.api.pipeline_instances().create.refute_called()
+ stubs.api.jobs().create.refute_called()
+
+ expect_component = copy.deepcopy(stubs.expect_job_spec)
+ self._adjust_script_params(expect_component)
expect_template = {
"components": {
"submit_wf.cwl": expect_component,
stubs.expect_pipeline_template_uuid + '\n')
+ @stubs
+ def test_create_name(self, stubs):
+ project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
+
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--create-workflow", "--debug",
+ "--project-uuid", project_uuid,
+ "--api=jobs",
+ "--name", "testing 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.api.pipeline_instances().create.refute_called()
+ stubs.api.jobs().create.refute_called()
+
+ expect_component = copy.deepcopy(stubs.expect_job_spec)
+ self._adjust_script_params(expect_component)
+ expect_template = {
+ "components": {
+ "testing 123": expect_component,
+ },
+ "name": "testing 123",
+ "owner_uuid": project_uuid,
+ }
+ stubs.api.pipeline_templates().create.assert_called_with(
+ body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
+
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_pipeline_template_uuid + '\n')
+
+
+ @stubs
+ def test_update_name(self, stubs):
+ project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
+
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--update-workflow", self.existing_template_uuid,
+ "--debug",
+ "--project-uuid", project_uuid,
+ "--api=jobs",
+ "--name", "testing 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.api.pipeline_instances().create.refute_called()
+ stubs.api.jobs().create.refute_called()
+
+ expect_component = copy.deepcopy(stubs.expect_job_spec)
+ self._adjust_script_params(expect_component)
+ expect_template = {
+ "components": {
+ "testing 123": expect_component,
+ },
+ "name": "testing 123",
+ "owner_uuid": project_uuid,
+ }
+ stubs.api.pipeline_templates().create.refute_called()
+ stubs.api.pipeline_templates().update.assert_called_with(
+ body=JsonDiffMatcher(expect_template), uuid=self.existing_template_uuid)
+
+ self.assertEqual(capture_stdout.getvalue(),
+ self.existing_template_uuid + '\n')
+
+
class TestCreateWorkflow(unittest.TestCase):
+ existing_workflow_uuid = "zzzzz-7fd4e-validworkfloyml"
+ expect_workflow = open("tests/wf/expect_packed.cwl").read()
+
@stubs
def test_create(self, stubs):
project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
exited = arvados_cwl.main(
["--create-workflow", "--debug",
+ "--api=containers",
"--project-uuid", project_uuid,
"tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
capture_stdout, sys.stderr, api_client=stubs.api)
stubs.api.pipeline_templates().create.refute_called()
stubs.api.container_requests().create.refute_called()
- with open("tests/wf/expect_packed.cwl") as f:
- expect_workflow = f.read()
-
body = {
"workflow": {
"owner_uuid": project_uuid,
"name": "submit_wf.cwl",
"description": "",
- "definition": expect_workflow
- }
+ "definition": self.expect_workflow,
+ }
+ }
+ stubs.api.workflows().create.assert_called_with(
+ body=JsonDiffMatcher(body))
+
+ self.assertEqual(capture_stdout.getvalue(),
+ stubs.expect_workflow_uuid + '\n')
+
+
+ @stubs
+ def test_create_name(self, stubs):
+ project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
+
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--create-workflow", "--debug",
+ "--api=containers",
+ "--project-uuid", project_uuid,
+ "--name", "testing 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ stubs.api.pipeline_templates().create.refute_called()
+ stubs.api.container_requests().create.refute_called()
+
+ body = {
+ "workflow": {
+ "owner_uuid": project_uuid,
+ "name": "testing 123",
+ "description": "",
+ "definition": self.expect_workflow,
+ }
}
stubs.api.workflows().create.assert_called_with(
body=JsonDiffMatcher(body))
self.assertEqual(capture_stdout.getvalue(),
stubs.expect_workflow_uuid + '\n')
+ @stubs
+ def test_incompatible_api(self, stubs):
+ capture_stderr = cStringIO.StringIO()
+ logging.getLogger('arvados.cwl-runner').addHandler(
+ logging.StreamHandler(capture_stderr))
+
+ exited = arvados_cwl.main(
+ ["--update-workflow", self.existing_workflow_uuid,
+ "--api=jobs",
+ "--debug",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ sys.stderr, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 1)
+ self.assertRegexpMatches(
+ capture_stderr.getvalue(),
+ "--update-workflow arg '{}' uses 'containers' API, but --api='jobs' specified".format(self.existing_workflow_uuid))
+
+ @stubs
+ def test_update(self, stubs):
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--update-workflow", self.existing_workflow_uuid,
+ "--debug",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ body = {
+ "workflow": {
+ "name": "submit_wf.cwl",
+ "description": "",
+ "definition": self.expect_workflow,
+ }
+ }
+ stubs.api.workflows().update.assert_called_with(
+ uuid=self.existing_workflow_uuid,
+ body=JsonDiffMatcher(body))
+ self.assertEqual(capture_stdout.getvalue(),
+ self.existing_workflow_uuid + '\n')
+
+
+ @stubs
+ def test_update_name(self, stubs):
+ capture_stdout = cStringIO.StringIO()
+
+ exited = arvados_cwl.main(
+ ["--update-workflow", self.existing_workflow_uuid,
+ "--debug", "--name", "testing 123",
+ "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
+ capture_stdout, sys.stderr, api_client=stubs.api)
+ self.assertEqual(exited, 0)
+
+ body = {
+ "workflow": {
+ "name": "testing 123",
+ "description": "",
+ "definition": self.expect_workflow,
+ }
+ }
+ stubs.api.workflows().update.assert_called_with(
+ uuid=self.existing_workflow_uuid,
+ body=JsonDiffMatcher(body))
+ self.assertEqual(capture_stdout.getvalue(),
+ self.existing_workflow_uuid + '\n')
+
class TestTemplateInputs(unittest.TestCase):
expect_template = {
"inputs_test.cwl": {
'runtime_constraints': {
'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
+ 'min_ram_mb_per_node': 1024
},
'script_parameters': {
'cwl:tool':
},
},
'repository': 'arvados',
- 'script_version': arvados_cwl.__version__,
+ 'script_version': 'master',
+ 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
'script': 'cwl-runner',
},
},
@stubs
def test_inputs_empty(self, stubs):
exited = arvados_cwl.main(
- ["--create-template", "--no-wait",
+ ["--create-template",
"tests/wf/inputs_test.cwl", "tests/order/empty_order.json"],
cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
self.assertEqual(exited, 0)
- expect_template = copy.deepcopy(self.expect_template)
- expect_template["owner_uuid"] = stubs.fake_user_uuid
-
stubs.api.pipeline_templates().create.assert_called_with(
- body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
+ body=JsonDiffMatcher(self.expect_template), ensure_unique_name=True)
@stubs
def test_inputs(self, stubs):
exited = arvados_cwl.main(
- ["--create-template", "--no-wait",
+ ["--create-template",
"tests/wf/inputs_test.cwl", "tests/order/inputs_test_order.json"],
cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
self.assertEqual(exited, 0)
- self.expect_template["owner_uuid"] = stubs.fake_user_uuid
-
expect_template = copy.deepcopy(self.expect_template)
- expect_template["owner_uuid"] = stubs.fake_user_uuid
params = expect_template[
"components"]["inputs_test.cwl"]["script_parameters"]
params["fileInput"]["value"] = '99999999999999999999999999999994+99/blorp.txt'
--- /dev/null
+import functools
+import mock
+import sys
+import unittest
+import json
+import logging
+import os
+
+import arvados
+import arvados.keep
+import arvados.collection
+import arvados_cwl
+
+from arvados_cwl.fsaccess import CollectionFetcher
+
+class TestUrljoin(unittest.TestCase):
+ def test_urljoin(self):
+ """Test path joining for keep references."""
+
+ cf = CollectionFetcher({}, None)
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/hw.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99", "hw.py"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/hw.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99/", "hw.py"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/hw.py#main",
+ cf.urljoin("keep:99999999999999999999999999999991+99", "hw.py#main"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/hw.py#main",
+ cf.urljoin("keep:99999999999999999999999999999991+99/hw.py", "#main"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/dir/hw.py#main",
+ cf.urljoin("keep:99999999999999999999999999999991+99/dir/hw.py", "#main"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/dir/wh.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99/dir/hw.py", "wh.py"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/wh.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99/dir/hw.py", "/wh.py"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/wh.py#main",
+ cf.urljoin("keep:99999999999999999999999999999991+99/dir/hw.py", "/wh.py#main"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/wh.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99/hw.py#main", "wh.py"))
+
+ self.assertEquals("keep:99999999999999999999999999999992+99",
+ cf.urljoin("keep:99999999999999999999999999999991+99", "keep:99999999999999999999999999999992+99"))
+
+ self.assertEquals("keep:99999999999999999999999999999991+99/dir/wh.py",
+ cf.urljoin("keep:99999999999999999999999999999991+99/dir/", "wh.py"))
+
+ def test_resolver(self):
+ pass
--- /dev/null
+$graph:
+- baseCommand: cat
+ class: CommandLineTool
+ id: '#submit_tool.cwl'
+ inputs:
+ - id: '#submit_tool.cwl/x'
+ inputBinding: {position: 1}
+ type: string
+ outputs: []
+ requirements:
+ - {class: DockerRequirement, dockerPull: 'debian:8'}
+- class: Workflow
+ id: '#main'
+ inputs:
+ - id: '#main/x'
+ type: string
+ outputs: []
+ steps:
+ - id: '#main/step1'
+ in:
+ - {id: '#main/step1/x', source: '#main/x'}
+ out: []
+ run: '#submit_tool.cwl'
+cwlVersion: v1.0
+cwlVersion: v1.0
$graph:
-- baseCommand: cat
- class: CommandLineTool
- id: '#submit_tool.cwl'
+- class: CommandLineTool
+ requirements:
+ - class: DockerRequirement
+ dockerPull: debian:8
inputs:
- - default: {class: File, location: 'keep:99999999999999999999999999999991+99/tool/blub.txt'}
- id: '#submit_tool.cwl/x'
- inputBinding: {position: 1}
+ - id: '#submit_tool.cwl/x'
type: File
+ default:
+ class: File
+ location: keep:99999999999999999999999999999991+99/tool/blub.txt
+ inputBinding:
+ position: 1
outputs: []
- requirements:
- - {class: DockerRequirement, dockerImageId: 'debian:8', dockerPull: 'debian:8'}
+ baseCommand: cat
+ id: '#submit_tool.cwl'
- class: Workflow
- id: '#main'
inputs:
- - default: {basename: blorp.txt, class: File, location: 'keep:99999999999999999999999999999991+99/input/blorp.txt'}
- id: '#main/x'
+ - id: '#main/x'
type: File
- - default: {basename: 99999999999999999999999999999998+99, class: Directory, location: 'keep:99999999999999999999999999999998+99'}
- id: '#main/y'
+ default: {class: File, location: 'keep:99999999999999999999999999999991+99/input/blorp.txt',
+ basename: blorp.txt}
+ - id: '#main/y'
type: Directory
- - default:
- basename: anonymous
- class: Directory
- listing:
- - {basename: renamed.txt, class: File, location: 'keep:99999999999999999999999999999998+99/file1.txt'}
- id: '#main/z'
+ default: {class: Directory, location: 'keep:99999999999999999999999999999998+99',
+ basename: 99999999999999999999999999999998+99}
+ - id: '#main/z'
type: Directory
+ default: {class: Directory, basename: anonymous, listing: [{basename: renamed.txt,
+ class: File, location: 'keep:99999999999999999999999999999998+99/file1.txt'}]}
outputs: []
steps:
- id: '#main/step1'
- {id: '#main/step1/x', source: '#main/x'}
out: []
run: '#submit_tool.cwl'
-cwlVersion: v1.0
+ id: '#main'
+cwlVersion: v1.0
$graph:
- class: Workflow
- hints:
- - {class: 'http://arvados.org/cwl#RunInSingleContainer'}
id: '#main'
inputs:
- - {id: '#main/sleeptime', type: int}
+ - type: int
+ id: '#main/sleeptime'
outputs:
- - {id: '#main/out', outputSource: '#main/sleep1/out', type: string}
- requirements:
- - {class: InlineJavascriptRequirement}
- - {class: ScatterFeatureRequirement}
- - {class: StepInputExpressionRequirement}
- - {class: SubworkflowFeatureRequirement}
+ - type: string
+ outputSource: '#main/sleep1/out'
+ id: '#main/out'
steps:
- - id: '#main/sleep1'
- in:
- - {id: '#main/sleep1/blurb', valueFrom: "${\n return String(inputs.sleeptime)\
- \ + \"b\";\n}\n"}
- - {id: '#main/sleep1/sleeptime', source: '#main/sleeptime'}
+ - in:
+ - valueFrom: |
+ ${
+ return String(inputs.sleeptime) + "b";
+ }
+ id: '#main/sleep1/blurb'
+ - source: '#main/sleeptime'
+ id: '#main/sleep1/sleeptime'
out: ['#main/sleep1/out']
run:
- baseCommand: sleep
class: CommandLineTool
inputs:
- - id: '#main/sleep1/sleeptime'
+ - type: int
inputBinding: {position: 1}
- type: int
+ id: '#main/sleep1/sleeptime'
outputs:
- - id: '#main/sleep1/out'
- outputBinding: {outputEval: out}
- type: string
-cwlVersion: v1.0
\ No newline at end of file
+ - type: string
+ outputBinding:
+ outputEval: out
+ id: '#main/sleep1/out'
+ baseCommand: sleep
+ id: '#main/sleep1'
+ requirements:
+ - {class: InlineJavascriptRequirement}
+ - {class: ScatterFeatureRequirement}
+ - {class: StepInputExpressionRequirement}
+ - {class: SubworkflowFeatureRequirement}
+ hints:
+ - class: http://arvados.org/cwl#RunInSingleContainer
\ No newline at end of file
--- /dev/null
+# Test case for arvados-cwl-runner
+#
+# Used to test whether scanning a workflow file for dependencies
+# (e.g. submit_tool.cwl) and uploading to Keep works as intended.
+
+class: Workflow
+cwlVersion: v1.0
+inputs:
+ x:
+ type: File
+ default:
+ class: File
+ location: keep:99999999999999999999999999999994+99/blorp.txt
+outputs: []
+steps:
+ step1:
+ in:
+ x: x
+ out: []
+ run: ../tool/submit_tool.cwl
--- /dev/null
+# Dockerfile for building an arvados/jobs Docker image from local git tree.
+#
+# Intended for use by developers working on arvados-python-client or
+# arvados-cwl-runner and need to run a crunch job with a custom package
+# version.
+#
+# Use arvados/build/build-dev-docker-jobs-image.sh to build.
+#
+# (This dockerfile file must be located in the arvados/sdk/ directory because
+# of the docker build root.)
+
+FROM debian:jessie
+MAINTAINER Ward Vandewege <ward@curoverse.com>
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get update -q && apt-get install -qy git python-pip python-virtualenv python-dev libcurl4-gnutls-dev libgnutls28-dev nodejs python-pyasn1-modules
+
+RUN pip install -U setuptools
+
+ARG sdk
+ARG runner
+ARG cwltool
+
+ADD python/dist/$sdk /tmp/
+ADD cwl/cwltool_dist/$cwltool /tmp/
+ADD cwl/dist/$runner /tmp/
+
+RUN cd /tmp/arvados-python-client-* && python setup.py install
+RUN if test -d /tmp/cwltool-* ; then cd /tmp/cwltool-* && python setup.py install ; fi
+RUN cd /tmp/arvados-cwl-runner-* && python setup.py install
+
+# Install dependencies and set up system.
+RUN /usr/sbin/adduser --disabled-password \
+ --gecos 'Crunch execution user' crunch && \
+ /usr/bin/install --directory --owner=crunch --group=crunch --mode=0700 /keep /tmp/crunch-src /tmp/crunch-job
+
+USER crunch
// callers who use a Client to initialize an
// arvadosclient.ArvadosClient.)
KeepServiceURIs []string `json:",omitempty"`
+
+ dd *DiscoveryDocument
}
// The default http.Client used by a Client with Insecure==true and
// DiscoveryDocument is the Arvados server's description of itself.
type DiscoveryDocument struct {
- DefaultCollectionReplication int `json:"defaultCollectionReplication"`
- BlobSignatureTTL int64 `json:"blobSignatureTtl"`
+ BasePath string `json:"basePath"`
+ DefaultCollectionReplication int `json:"defaultCollectionReplication"`
+ BlobSignatureTTL int64 `json:"blobSignatureTtl"`
+ Schemas map[string]Schema `json:"schemas"`
+ Resources map[string]Resource `json:"resources"`
+}
+
+type Resource struct {
+ Methods map[string]ResourceMethod `json:"methods"`
+}
+
+type ResourceMethod struct {
+ HTTPMethod string `json:"httpMethod"`
+ Path string `json:"path"`
+ Response MethodResponse `json:"response"`
+}
+
+type MethodResponse struct {
+ Ref string `json:"$ref"`
+}
+
+type Schema struct {
+ UUIDPrefix string `json:"uuidPrefix"`
}
// DiscoveryDocument returns a *DiscoveryDocument. The returned object
// should not be modified: the same object may be returned by
// subsequent calls.
func (c *Client) DiscoveryDocument() (*DiscoveryDocument, error) {
+ if c.dd != nil {
+ return c.dd, nil
+ }
var dd DiscoveryDocument
- return &dd, c.RequestAndDecode(&dd, "GET", "discovery/v1/apis/arvados/v1/rest", nil, nil)
+ err := c.RequestAndDecode(&dd, "GET", "discovery/v1/apis/arvados/v1/rest", nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ c.dd = &dd
+ return c.dd, nil
+}
+
+func (c *Client) modelForUUID(dd *DiscoveryDocument, uuid string) (string, error) {
+ if len(uuid) != 27 {
+ return "", fmt.Errorf("invalid UUID: %q", uuid)
+ }
+ infix := uuid[6:11]
+ var model string
+ for m, s := range dd.Schemas {
+ if s.UUIDPrefix == infix {
+ model = m
+ break
+ }
+ }
+ if model == "" {
+ return "", fmt.Errorf("unrecognized type portion %q in UUID %q", infix, uuid)
+ }
+ return model, nil
+}
+
+func (c *Client) KindForUUID(uuid string) (string, error) {
+ dd, err := c.DiscoveryDocument()
+ if err != nil {
+ return "", err
+ }
+ model, err := c.modelForUUID(dd, uuid)
+ if err != nil {
+ return "", err
+ }
+ return "arvados#" + strings.ToLower(model[:1]) + model[1:], nil
+}
+
+func (c *Client) PathForUUID(method, uuid string) (string, error) {
+ dd, err := c.DiscoveryDocument()
+ if err != nil {
+ return "", err
+ }
+ model, err := c.modelForUUID(dd, uuid)
+ if err != nil {
+ return "", err
+ }
+ var resource string
+ for r, rsc := range dd.Resources {
+ if rsc.Methods["get"].Response.Ref == model {
+ resource = r
+ break
+ }
+ }
+ if resource == "" {
+ return "", fmt.Errorf("no resource for model: %q", model)
+ }
+ m, ok := dd.Resources[resource].Methods[method]
+ if !ok {
+ return "", fmt.Errorf("no method %q for resource %q", method, resource)
+ }
+ path := dd.BasePath + strings.Replace(m.Path, "{uuid}", uuid, -1)
+ if path[0] == '/' {
+ path = path[1:]
+ }
+ return path, nil
}
// Collection is an arvados#collection resource.
type Collection struct {
UUID string `json:"uuid,omitempty"`
- ExpiresAt *time.Time `json:"expires_at,omitempty"`
+ TrashAt *time.Time `json:"trash_at,omitempty"`
ManifestText string `json:"manifest_text,omitempty"`
+ UnsignedManifestText string `json:"unsigned_manifest_text,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
ModifiedAt *time.Time `json:"modified_at,omitempty"`
PortableDataHash string `json:"portable_data_hash,omitempty"`
ReplicationConfirmed *int `json:"replication_confirmed,omitempty"`
ReplicationConfirmedAt *time.Time `json:"replication_confirmed_at,omitempty"`
ReplicationDesired *int `json:"replication_desired,omitempty"`
+ DeleteAt *time.Time `json:"delete_at,omitempty"`
+ IsTrashed bool `json:"is_trashed,omitempty"`
}
// SizedDigests returns the hash+size part of each data block
// referenced by the collection.
func (c *Collection) SizedDigests() ([]SizedDigest, error) {
- if c.ManifestText == "" && c.PortableDataHash != "d41d8cd98f00b204e9800998ecf8427e+0" {
+ manifestText := c.ManifestText
+ if manifestText == "" {
+ manifestText = c.UnsignedManifestText
+ }
+ if manifestText == "" && c.PortableDataHash != "d41d8cd98f00b204e9800998ecf8427e+0" {
// TODO: Check more subtle forms of corruption, too
return nil, fmt.Errorf("manifest is missing")
}
var sds []SizedDigest
- scanner := bufio.NewScanner(strings.NewReader(c.ManifestText))
- scanner.Buffer(make([]byte, 1048576), len(c.ManifestText))
+ scanner := bufio.NewScanner(strings.NewReader(manifestText))
+ scanner.Buffer(make([]byte, 1048576), len(manifestText))
for scanner.Scan() {
line := scanner.Text()
tokens := strings.Split(line, " ")
// Container is an arvados#container resource.
type Container struct {
- UUID string `json:"uuid"`
- Command []string `json:"command"`
- ContainerImage string `json:"container_image"`
- Cwd string `json:"cwd"`
- Environment map[string]string `json:"environment"`
- LockedByUUID string `json:"locked_by_uuid"`
- Mounts map[string]Mount `json:"mounts"`
- Output string `json:"output"`
- OutputPath string `json:"output_path"`
- Priority int `json:"priority"`
- RuntimeConstraints RuntimeConstraints `json:"runtime_constraints"`
- State ContainerState `json:"state"`
+ UUID string `json:"uuid"`
+ Command []string `json:"command"`
+ ContainerImage string `json:"container_image"`
+ Cwd string `json:"cwd"`
+ Environment map[string]string `json:"environment"`
+ LockedByUUID string `json:"locked_by_uuid"`
+ Mounts map[string]Mount `json:"mounts"`
+ Output string `json:"output"`
+ OutputPath string `json:"output_path"`
+ Priority int `json:"priority"`
+ RuntimeConstraints RuntimeConstraints `json:"runtime_constraints"`
+ State ContainerState `json:"state"`
+ SchedulingParameters SchedulingParameters `json:"scheduling_parameters"`
}
// Mount is special behavior to attach to a filesystem path or device.
// CPU) and network connectivity.
type RuntimeConstraints struct {
API *bool
- RAM int `json:"ram"`
- VCPUs int `json:"vcpus"`
- KeepCacheRAM int `json:"keep_cache_ram"`
- Partition []string `json:"partition"`
+ RAM int `json:"ram"`
+ VCPUs int `json:"vcpus"`
+ KeepCacheRAM int `json:"keep_cache_ram"`
+}
+
+// SchedulingParameters specify a container's scheduling parameters
+// such as Partitions
+type SchedulingParameters struct {
+ Partitions []string `json:"partitions"`
}
// ContainerList is an arvados#containerList resource.
--- /dev/null
+package arvados
+
+import (
+ "time"
+)
+
+// Log is an arvados#log record
+type Log struct {
+ ID uint64 `json:"id"`
+ UUID string `json:"uuid"`
+ ObjectUUID string `json:"object_uuid"`
+ ObjectOwnerUUID string `json:"object_owner_uuid"`
+ EventType string `json:"event_type"`
+ EventAt *time.Time `json:"event,omitempty"`
+ Properties map[string]interface{} `json:"properties"`
+ CreatedAt *time.Time `json:"created_at,omitempty"`
+}
+
+// LogList is an arvados#logList resource.
+type LogList struct {
+ Items []Log `json:"items"`
+ ItemsAvailable int `json:"items_available"`
+ Offset int `json:"offset"`
+ Limit int `json:"limit"`
+}
// ResourceListParams expresses which results are requested in a
// list/index API.
type ResourceListParams struct {
- Select []string `json:"select,omitempty"`
- Filters []Filter `json:"filters,omitempty"`
- Limit *int `json:"limit,omitempty"`
- Offset int `json:"offset,omitempty"`
- Order string `json:"order,omitempty"`
- Distinct bool `json:"distinct,omitempty"`
- Count bool `json:"count,omitempty"`
+ Select []string `json:"select,omitempty"`
+ Filters []Filter `json:"filters,omitempty"`
+ IncludeTrash bool `json:"include_trash,omitempty"`
+ Limit *int `json:"limit,omitempty"`
+ Offset int `json:"offset,omitempty"`
+ Order string `json:"order,omitempty"`
+ Distinct bool `json:"distinct,omitempty"`
+ Count bool `json:"count,omitempty"`
}
// A Filter restricts the set of records returned by a list/index API.
import (
"bytes"
"crypto/tls"
+ "crypto/x509"
"encoding/json"
"errors"
"fmt"
"io"
+ "io/ioutil"
"net/http"
"net/url"
"os"
Retries int
}
+var CertFiles = []string{
+ "/etc/arvados/ca-certificates.crt",
+ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
+}
+
+// MakeTLSConfig sets up TLS configuration for communicating with Arvados and Keep services.
+func MakeTLSConfig(insecure bool) *tls.Config {
+ tlsconfig := tls.Config{InsecureSkipVerify: insecure}
+
+ if !insecure {
+ // Look for /etc/arvados/ca-certificates.crt in addition to normal system certs.
+ certs := x509.NewCertPool()
+ for _, file := range CertFiles {
+ data, err := ioutil.ReadFile(file)
+ if err == nil {
+ success := certs.AppendCertsFromPEM(data)
+ if !success {
+ fmt.Printf("Unable to load any certificates from %v", file)
+ } else {
+ tlsconfig.RootCAs = certs
+ break
+ }
+ }
+ }
+ // Will use system default CA roots instead.
+ }
+
+ return &tlsconfig
+}
+
// New returns an ArvadosClient using the given arvados.Client
// configuration. This is useful for callers who load arvados.Client
// fields from configuration files but still need to use the
// arvadosclient.ArvadosClient package.
func New(c *arvados.Client) (*ArvadosClient, error) {
- return &ArvadosClient{
+ ac := &ArvadosClient{
Scheme: "https",
ApiServer: c.APIHost,
ApiToken: c.AuthToken,
ApiInsecure: c.Insecure,
Client: &http.Client{Transport: &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: c.Insecure}}},
+ TLSClientConfig: MakeTLSConfig(c.Insecure)}},
External: false,
Retries: 2,
lastClosedIdlesAt: time.Now(),
- }, nil
+ }
+
+ return ac, nil
}
// MakeArvadosClient creates a new ArvadosClient using the standard
ApiToken: os.Getenv("ARVADOS_API_TOKEN"),
ApiInsecure: insecure,
Client: &http.Client{Transport: &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure}}},
+ TLSClientConfig: MakeTLSConfig(insecure)}},
External: external,
Retries: 2}
}
return nil
}
+
+// Dump returns a YAML representation of cfg.
+func Dump(cfg interface{}) ([]byte, error) {
+ return yaml.Marshal(cfg)
+}
package main
import (
- "crypto/x509"
"encoding/json"
"fmt"
"git.curoverse.com/arvados.git/sdk/go/arvados"
"io"
"io/ioutil"
"log"
- "net/http"
"os"
"os/exec"
"os/signal"
log.Fatal(err)
}
- // Container may not have certificates installed, so need to look for
- // /etc/arvados/ca-certificates.crt in addition to normal system certs.
- var certFiles = []string{
- "/etc/ssl/certs/ca-certificates.crt", // Debian
- "/etc/pki/tls/certs/ca-bundle.crt", // Red Hat
- "/etc/arvados/ca-certificates.crt",
- }
-
- certs := x509.NewCertPool()
- for _, file := range certFiles {
- data, err := ioutil.ReadFile(file)
- if err == nil {
- log.Printf("Using TLS certificates at %v", file)
- certs.AppendCertsFromPEM(data)
- }
- }
- api.Client.Transport.(*http.Transport).TLSClientConfig.RootCAs = certs
-
jobUuid := os.Getenv("JOB_UUID")
taskUuid := os.Getenv("TASK_UUID")
tmpdir := os.Getenv("TASK_WORK")
--- /dev/null
+package ctxlog
+
+import (
+ "context"
+
+ "github.com/Sirupsen/logrus"
+)
+
+var (
+ loggerCtxKey = new(int)
+ rootLogger = logrus.New()
+)
+
+const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+
+// Context returns a new child context such that FromContext(child)
+// returns the given logger.
+func Context(ctx context.Context, logger *logrus.Entry) context.Context {
+ return context.WithValue(ctx, loggerCtxKey, logger)
+}
+
+// FromContext returns the logger suitable for the given context -- the one
+// attached by contextWithLogger() if applicable, otherwise the
+// top-level logger with no fields/values.
+func FromContext(ctx context.Context) *logrus.Entry {
+ if ctx != nil {
+ if logger, ok := ctx.Value(loggerCtxKey).(*logrus.Entry); ok {
+ return logger
+ }
+ }
+ return rootLogger.WithFields(nil)
+}
+
+// SetLevel sets the current logging level. See logrus for level
+// names.
+func SetLevel(level string) {
+ lvl, err := logrus.ParseLevel(level)
+ if err != nil {
+ logrus.Fatal(err)
+ }
+ rootLogger.Level = lvl
+}
+
+// SetFormat sets the current logging format to "json" or "text".
+func SetFormat(format string) {
+ switch format {
+ case "text":
+ rootLogger.Formatter = &logrus.TextFormatter{
+ FullTimestamp: true,
+ TimestampFormat: rfc3339NanoFixed,
+ }
+ case "json":
+ rootLogger.Formatter = &logrus.JSONFormatter{
+ TimestampFormat: rfc3339NanoFixed,
+ }
+ default:
+ logrus.WithField("LogFormat", format).Fatal("unknown log format")
+ }
+}
--- /dev/null
+package httpserver
+
+import (
+ "strconv"
+ "sync"
+ "time"
+)
+
+// IDGenerator generates alphanumeric strings suitable for use as
+// unique IDs (a given IDGenerator will never return the same ID
+// twice).
+type IDGenerator struct {
+ // Prefix is prepended to each returned ID.
+ Prefix string
+
+ lastID int64
+ mtx sync.Mutex
+}
+
+// Next returns a new ID string. It is safe to call Next from multiple
+// goroutines.
+func (g *IDGenerator) Next() string {
+ id := time.Now().UnixNano()
+ g.mtx.Lock()
+ if id <= g.lastID {
+ id = g.lastID + 1
+ }
+ g.lastID = id
+ g.mtx.Unlock()
+ return g.Prefix + strconv.FormatInt(id, 36)
+}
"net/http"
)
+// RequestCounter is an http.Handler that tracks the number of
+// requests in progress.
+type RequestCounter interface {
+ http.Handler
+
+ // Current() returns the number of requests in progress.
+ Current() int
+
+ // Max() returns the maximum number of concurrent requests
+ // that will be accepted.
+ Max() int
+}
+
type limiterHandler struct {
requests chan struct{}
handler http.Handler
}
-func NewRequestLimiter(maxRequests int, handler http.Handler) http.Handler {
+// NewRequestLimiter returns a RequestCounter that delegates up to
+// maxRequests at a time to the given handler, and responds 503 to all
+// incoming requests beyond that limit.
+func NewRequestLimiter(maxRequests int, handler http.Handler) RequestCounter {
return &limiterHandler{
requests: make(chan struct{}, maxRequests),
handler: handler,
}
}
+func (h *limiterHandler) Current() int {
+ return len(h.requests)
+}
+
+func (h *limiterHandler) Max() int {
+ return cap(h.requests)
+}
+
func (h *limiterHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
select {
case h.requests <- struct{}{}:
import (
"bytes"
"crypto/md5"
- "crypto/tls"
"errors"
"fmt"
"git.curoverse.com/arvados.git/sdk/go/arvadosclient"
Arvados: arv,
Want_replicas: defaultReplicationLevel,
Client: &http.Client{Transport: &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: arv.ApiInsecure}}},
+ TLSClientConfig: arvadosclient.MakeTLSConfig(arv.ApiInsecure)}},
Retries: 2,
}
return kc
}
func (kc *KeepClient) getOrHead(method string, locator string) (io.ReadCloser, int64, string, error) {
+ if strings.HasPrefix(locator, "d41d8cd98f00b204e9800998ecf8427e+0") {
+ return ioutil.NopCloser(bytes.NewReader(nil)), 0, "", nil
+ }
+
var errs []string
tries_remaining := 1 + kc.Retries
import (
"crypto/md5"
- "flag"
"fmt"
"git.curoverse.com/arvados.git/sdk/go/arvadosclient"
"git.curoverse.com/arvados.git/sdk/go/arvadostest"
var _ = Suite(&ServerRequiredSuite{})
var _ = Suite(&StandaloneSuite{})
-var no_server = flag.Bool("no-server", false, "Skip 'ServerRequireSuite'")
-
// Tests that require the Keep server running
type ServerRequiredSuite struct{}
}
func (s *ServerRequiredSuite) SetUpSuite(c *C) {
- if *no_server {
- c.Skip("Skipping tests that require server")
- return
- }
arvadostest.StartAPI()
arvadostest.StartKeep(2, false)
}
func (s *ServerRequiredSuite) TearDownSuite(c *C) {
- if *no_server {
- return
- }
arvadostest.StopKeep(2)
arvadostest.StopAPI()
}
c.Check(r, Equals, nil)
}
+func (s *StandaloneSuite) TestGetEmptyBlock(c *C) {
+ st := Error404Handler{make(chan string, 1)}
+
+ ks := RunFakeKeepServer(st)
+ defer ks.listener.Close()
+
+ arv, err := arvadosclient.MakeArvadosClient()
+ kc, _ := MakeKeepClient(arv)
+ arv.ApiToken = "abc123"
+ kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
+
+ r, n, url2, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e+0")
+ c.Check(err, IsNil)
+ c.Check(n, Equals, int64(0))
+ c.Check(url2, Equals, "")
+ c.Assert(r, NotNil)
+ buf, err := ioutil.ReadAll(r)
+ c.Check(err, IsNil)
+ c.Check(buf, DeepEquals, []byte{})
+}
+
func (s *StandaloneSuite) TestGetFail(c *C) {
hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
+++ /dev/null
-// Logger periodically writes a log to the Arvados SDK.
-//
-// This package is useful for maintaining a log object that is updated
-// over time. This log object will be periodically written to the log,
-// as specified by WriteInterval in the Params.
-//
-// This package is safe for concurrent use as long as:
-// The maps passed to a LogMutator are not accessed outside of the
-// LogMutator
-//
-// Usage:
-// arvLogger := logger.NewLogger(params)
-// arvLogger.Update(func(properties map[string]interface{},
-// entry map[string]interface{}) {
-// // Modifiy properties and entry however you want
-// // properties is a shortcut for entry["properties"].(map[string]interface{})
-// // properties can take any (valid) values you want to give it,
-// // entry will only take the fields listed at
-// // http://doc.arvados.org/api/schema/Log.html
-// // Valid values for properties are anything that can be json
-// // encoded (i.e. will not error if you call json.Marshal() on it.
-// })
-package logger
-
-import (
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "log"
- "time"
-)
-
-const (
- startSuffix = "-start"
- partialSuffix = "-partial"
- finalSuffix = "-final"
- numberNoMoreWorkMessages = 2 // To return from FinalUpdate() & Work().
-)
-
-type LoggerParams struct {
- Client *arvadosclient.ArvadosClient // The client we use to write log entries
- EventTypePrefix string // The prefix we use for the event type in the log entry
- WriteInterval time.Duration // Wait at least this long between log writes
-}
-
-// A LogMutator is a function which modifies the log entry.
-// It takes two maps as arguments, properties is the first and entry
-// is the second
-// properties is a shortcut for entry["properties"].(map[string]interface{})
-// properties can take any values you want to give it.
-// entry will only take the fields listed at http://doc.arvados.org/api/schema/Log.html
-// properties and entry are only safe to access inside the LogMutator,
-// they should not be stored anywhere, otherwise you'll risk
-// concurrent access.
-type LogMutator func(map[string]interface{}, map[string]interface{})
-
-// A Logger is used to build up a log entry over time and write every
-// version of it.
-type Logger struct {
- // The data we write
- data map[string]interface{} // The entire map that we give to the api
- entry map[string]interface{} // Convenience shortcut into data
- properties map[string]interface{} // Convenience shortcut into data
-
- params LoggerParams // Parameters we were given
-
- // Variables to coordinate updating and writing.
- modified bool // Has this data been modified since the last write?
- workToDo chan LogMutator // Work to do in the worker thread.
- writeTicker *time.Ticker // On each tick we write the log data to arvados, if it has been modified.
- hasWritten bool // Whether we've written at all yet.
- noMoreWork chan bool // Signals that we're done writing.
-
- writeHooks []LogMutator // Mutators we call before each write.
-}
-
-// Create a new logger based on the specified parameters.
-func NewLogger(params LoggerParams) (l *Logger, err error) {
- // sanity check parameters
- if ¶ms.Client == nil {
- err = fmt.Errorf("Nil arvados client in LoggerParams passed in to NewLogger()")
- return
- }
- if params.EventTypePrefix == "" {
- err = fmt.Errorf("Empty event type prefix in LoggerParams passed in to NewLogger()")
- return
- }
-
- l = &Logger{
- data: make(map[string]interface{}),
- entry: make(map[string]interface{}),
- properties: make(map[string]interface{}),
- params: params,
- workToDo: make(chan LogMutator, 10),
- writeTicker: time.NewTicker(params.WriteInterval),
- noMoreWork: make(chan bool, numberNoMoreWorkMessages)}
-
- l.data["log"] = l.entry
- l.entry["properties"] = l.properties
-
- // Start the worker goroutine.
- go l.work()
-
- return l, nil
-}
-
-// Exported functions will be called from other goroutines, therefore
-// all they are allowed to do is enqueue work to be done in the worker
-// goroutine.
-
-// Enqueues an update. This will happen in another goroutine after
-// this method returns.
-func (l *Logger) Update(mutator LogMutator) {
- l.workToDo <- mutator
-}
-
-// Similar to Update(), but writes the log entry as soon as possible
-// (ignoring MinimumWriteInterval) and blocks until the entry has been
-// written. This is useful if you know that you're about to quit
-// (e.g. if you discovered a fatal error, or you're finished), since
-// go will not wait for timers (including the pending write timer) to
-// go off before exiting.
-func (l *Logger) FinalUpdate(mutator LogMutator) {
- // TODO(misha): Consider not accepting any future updates somehow,
- // since they won't get written if they come in after this.
-
- // Stop the periodic write ticker. We'll perform the final write
- // before returning from this function.
- l.workToDo <- func(p map[string]interface{}, e map[string]interface{}) {
- l.writeTicker.Stop()
- }
-
- // Apply the final update
- l.workToDo <- mutator
-
- // Perform the final write and signal that we can return.
- l.workToDo <- func(p map[string]interface{}, e map[string]interface{}) {
- l.write(true)
- for i := 0; i < numberNoMoreWorkMessages; {
- l.noMoreWork <- true
- }
- }
-
- // Wait until we've performed the write.
- <-l.noMoreWork
-}
-
-// Adds a hook which will be called every time this logger writes an entry.
-func (l *Logger) AddWriteHook(hook LogMutator) {
- // We do the work in a LogMutator so that it happens in the worker
- // goroutine.
- l.workToDo <- func(p map[string]interface{}, e map[string]interface{}) {
- l.writeHooks = append(l.writeHooks, hook)
- }
-}
-
-// The worker loop
-func (l *Logger) work() {
- for {
- select {
- case <-l.writeTicker.C:
- if l.modified {
- l.write(false)
- l.modified = false
- }
- case mutator := <-l.workToDo:
- mutator(l.properties, l.entry)
- l.modified = true
- case <-l.noMoreWork:
- return
- }
- }
-}
-
-// Actually writes the log entry.
-func (l *Logger) write(isFinal bool) {
-
- // Run all our hooks
- for _, hook := range l.writeHooks {
- hook(l.properties, l.entry)
- }
-
- // Update the event type.
- if isFinal {
- l.entry["event_type"] = l.params.EventTypePrefix + finalSuffix
- } else if l.hasWritten {
- l.entry["event_type"] = l.params.EventTypePrefix + partialSuffix
- } else {
- l.entry["event_type"] = l.params.EventTypePrefix + startSuffix
- }
- l.hasWritten = true
-
- // Write the log entry.
- // This is a network write and will take a while, which is bad
- // because we're blocking all the other work on this goroutine.
- //
- // TODO(misha): Consider rewriting this so that we can encode l.data
- // into a string, and then perform the actual write in another
- // routine. This will be tricky and will require support in the
- // client.
- err := l.params.Client.Create("logs", l.data, nil)
- if err != nil {
- log.Printf("Received error writing %v: %v", l.data, err)
- }
-}
+++ /dev/null
-// Helper methods for interacting with Logger.
-package logger
-
-// Retrieves the map[string]interface{} stored at parent[key] if it
-// exists, otherwise it makes it and stores it there.
-// This is useful for logger because you may not know if a map you
-// need has already been created.
-func GetOrCreateMap(
- parent map[string]interface{},
- key string) (child map[string]interface{}) {
- read, exists := parent[key]
- if exists {
- child = read.(map[string]interface{})
-
- } else {
- child = make(map[string]interface{})
- parent[key] = child
- }
- return
-}
--- /dev/null
+package stats
+
+import (
+ "fmt"
+ "strconv"
+ "time"
+)
+
+// Duration is a duration that is displayed as a number of seconds in
+// fixed-point notation.
+type Duration time.Duration
+
+// MarshalJSON implements json.Marshaler.
+func (d Duration) MarshalJSON() ([]byte, error) {
+ return []byte(d.String()), nil
+}
+
+// String implements fmt.Stringer.
+func (d Duration) String() string {
+ return fmt.Sprintf("%.6f", time.Duration(d).Seconds())
+}
+
+// UnmarshalJSON implements json.Unmarshaler
+func (d *Duration) UnmarshalJSON(data []byte) error {
+ return d.Set(string(data))
+}
+
+// Value implements flag.Value
+func (d *Duration) Set(s string) error {
+ sec, err := strconv.ParseFloat(s, 64)
+ if err == nil {
+ *d = Duration(sec * float64(time.Second))
+ }
+ return err
+}
--- /dev/null
+package stats
+
+import (
+ "testing"
+ "time"
+)
+
+func TestString(t *testing.T) {
+ d := Duration(123123123123 * time.Nanosecond)
+ if s, expect := d.String(), "123.123123"; s != expect {
+ t.Errorf("got %s, expect %s", s, expect)
+ }
+}
+
+func TestSet(t *testing.T) {
+ var d Duration
+ if err := d.Set("123.456"); err != nil {
+ t.Fatal(err)
+ }
+ if got, expect := time.Duration(d).Nanoseconds(), int64(123456000000); got != expect {
+ t.Errorf("got %d, expect %d", got, expect)
+ }
+}
+++ /dev/null
-/* Helper methods for dealing with responses from API Server. */
-
-package util
-
-import (
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
-)
-
-func UserIsAdmin(arv *arvadosclient.ArvadosClient) (is_admin bool, err error) {
- type user struct {
- IsAdmin bool `json:"is_admin"`
- }
- var u user
- err = arv.Call("GET", "users", "", "current", nil, &u)
- return u.IsAdmin, err
-}
-
-// Returns the total count of a particular type of resource
-//
-// resource - the arvados resource to count
-// return
-// count - the number of items of type resource the api server reports, if no error
-// err - error accessing the resource, or nil if no error
-func NumberItemsAvailable(client *arvadosclient.ArvadosClient, resource string) (count int, err error) {
- var response struct {
- ItemsAvailable int `json:"items_available"`
- }
- sdkParams := arvadosclient.Dict{"limit": 0}
- err = client.List(resource, sdkParams, &response)
- if err == nil {
- count = response.ItemsAvailable
- }
- return
-}
--- /dev/null
+import pkg_resources
+
+__version__ = pkg_resources.require('arvados-python-client')[0].version
return
self._keep.get(b)
except Exception:
- pass
+ _logger.exception("Exception doing block prefetch")
@synchronized
def start_get_threads(self):
def writable(self):
return self.parent.writable()
+ @synchronized
+ def permission_expired(self, as_of_dt=None):
+ """Returns True if any of the segment's locators is expired"""
+ for r in self._segments:
+ if KeepLocator(r.locator).permission_expired(as_of_dt):
+ return True
+ return False
+
@synchronized
def segments(self):
return copy.copy(self._segments)
def find(self, path):
"""Recursively search the specified file path.
- May return either a Collection or ArvadosFile. Return None if not
+ May return either a Collection or ArvadosFile. Return None if not
found.
+ If path is invalid (ex: starts with '/'), an IOError exception will be
+ raised.
"""
if not path:
raise errors.ArgumentError("Parameter 'path' is empty.")
pathcomponents = path.split("/", 1)
+ if pathcomponents[0] == '':
+ raise IOError(errno.ENOTDIR, "Not a directory", pathcomponents[0])
+
item = self._items.get(pathcomponents[0])
- if len(pathcomponents) == 1:
+ if item is None:
+ return None
+ elif len(pathcomponents) == 1:
return item
else:
if isinstance(item, RichCollectionBase):
if target_dir is None:
raise IOError(errno.ENOENT, "Target directory not found", target_name)
- if target_name in target_dir and isinstance(self[target_name], RichCollectionBase) and sourcecomponents:
+ if target_name in target_dir and isinstance(target_dir[target_name], RichCollectionBase) and sourcecomponents:
target_dir = target_dir[target_name]
target_name = sourcecomponents[-1]
import arvados.util
import arvados.commands._util as arv_cmd
import arvados.commands.keepdocker
+import ruamel.yaml as yaml
from arvados.api import OrderedJsonModel
+from arvados._version import __version__
COMMIT_HASH_RE = re.compile(r'^[0-9a-f]{1,40}$')
def main():
copy_opts = argparse.ArgumentParser(add_help=False)
+ copy_opts.add_argument(
+ '--version', action='version', version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
copy_opts.add_argument(
'-v', '--verbose', dest='verbose', action='store_true',
help='Verbose output.')
copy_opts.set_defaults(recursive=True)
parser = argparse.ArgumentParser(
- description='Copy a pipeline instance, template or collection from one Arvados instance to another.',
+ description='Copy a pipeline instance, template, workflow, or collection from one Arvados instance to another.',
parents=[copy_opts, arv_cmd.retry_opt])
args = parser.parse_args()
set_src_owner_uuid(src_arv.pipeline_templates(), args.object_uuid, args)
result = copy_pipeline_template(args.object_uuid,
src_arv, dst_arv, args)
+ elif t == 'Workflow':
+ set_src_owner_uuid(src_arv.workflows(), args.object_uuid, args)
+ result = copy_workflow(args.object_uuid, src_arv, dst_arv, args)
else:
abort("cannot copy object {} of type {}".format(args.object_uuid, t))
return dst.pipeline_templates().create(body=pt, ensure_unique_name=True).execute(num_retries=args.retries)
+# copy_workflow(wf_uuid, src, dst, args)
+#
+# Copies a workflow identified by wf_uuid from src to dst.
+#
+# If args.recursive is True, also copy any collections
+# referenced in the workflow definition yaml.
+#
+# The owner_uuid of the new workflow is set to any given
+# project_uuid or the user who copied the template.
+#
+# Returns the copied workflow object.
+#
+def copy_workflow(wf_uuid, src, dst, args):
+ # fetch the workflow from the source instance
+ wf = src.workflows().get(uuid=wf_uuid).execute(num_retries=args.retries)
+
+ # copy collections and docker images
+ if args.recursive:
+ wf_def = yaml.safe_load(wf["definition"])
+ if wf_def is not None:
+ locations = []
+ docker_images = {}
+ graph = wf_def.get('$graph', None)
+ if graph is not None:
+ workflow_collections(graph, locations, docker_images)
+ else:
+ workflow_collections(wf_def, locations, docker_images)
+
+ if locations:
+ copy_collections(locations, src, dst, args)
+
+ for image in docker_images:
+ copy_docker_image(image, docker_images[image], src, dst, args)
+
+ # copy the workflow itself
+ del wf['uuid']
+ wf['owner_uuid'] = args.project_uuid
+ return dst.workflows().create(body=wf).execute(num_retries=args.retries)
+
+def workflow_collections(obj, locations, docker_images):
+ if isinstance(obj, dict):
+ loc = obj.get('location', None)
+ if loc is not None:
+ if loc.startswith("keep:"):
+ locations.append(loc[5:])
+
+ docker_image = obj.get('dockerImageId', None) or obj.get('dockerPull', None)
+ if docker_image is not None:
+ ds = docker_image.split(":", 1)
+ tag = ds[1] if len(ds)==2 else 'latest'
+ docker_images[ds[0]] = tag
+
+ for x in obj:
+ workflow_collections(obj[x], locations, docker_images)
+ elif isinstance(obj, list):
+ for x in obj:
+ workflow_collections(x, locations, docker_images)
+
# copy_collections(obj, src, dst, args)
#
# Recursively copies all collections referenced by 'obj' from src
import arvados.commands.put as arv_put
import ciso8601
+from arvados._version import __version__
+
EARLIEST_DATETIME = datetime.datetime(datetime.MINYEAR, 1, 1, 0, 0, 0)
STAT_CACHE_ERRORS = (IOError, OSError, ValueError)
'DockerImage', ['repo', 'tag', 'hash', 'created', 'vsize'])
keepdocker_parser = argparse.ArgumentParser(add_help=False)
+keepdocker_parser.add_argument(
+ '--version', action='version', version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
keepdocker_parser.add_argument(
'-f', '--force', action='store_true', default=False,
help="Re-upload the image even if it already exists on the server")
from __future__ import print_function
import argparse
+import sys
import arvados
import arvados.commands._util as arv_cmd
+from arvados._version import __version__
+
def parse_args(args):
parser = argparse.ArgumentParser(
description='List contents of a manifest',
help="""Collection UUID or locator""")
parser.add_argument('-s', action='store_true',
help="""List file sizes, in KiB.""")
+ parser.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
return parser.parse_args(args)
import arvados
import arvados.collection
import base64
+import copy
import datetime
import errno
import fcntl
import hashlib
import json
+import logging
import os
import pwd
-import time
+import re
import signal
import socket
import sys
import tempfile
import threading
-import copy
-import logging
+import time
from apiclient import errors as apiclient_errors
+from arvados._version import __version__
import arvados.commands._util as arv_cmd
upload_opts = argparse.ArgumentParser(add_help=False)
+upload_opts.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
upload_opts.add_argument('paths', metavar='path', type=str, nargs='*',
help="""
Local file or directory. Default: read from standard input.
_group = upload_opts.add_mutually_exclusive_group()
_group.add_argument('--max-manifest-depth', type=int, metavar='N',
- default=-1, help="""
-Maximum depth of directory tree to represent in the manifest
-structure. A directory structure deeper than this will be represented
-as a single stream in the manifest. If N=0, the manifest will contain
-a single stream. Default: -1 (unlimited), i.e., exactly one manifest
-stream per filesystem directory that contains files.
-""")
+ default=-1, help=argparse.SUPPRESS)
_group.add_argument('--normalize', action='store_true',
help="""
data.
""")
+_group.add_argument('--dry-run', action='store_true', default=False,
+ help="""
+Don't actually upload files, but only check if any file should be
+uploaded. Exit with code=2 when files are pending for upload.
+""")
+
_group = upload_opts.add_mutually_exclusive_group()
_group.add_argument('--as-stream', action='store_true', dest='stream',
manifest.
""")
+upload_opts.add_argument('--update-collection', type=str, default=None,
+ dest='update_collection', metavar="UUID", help="""
+Update an existing collection identified by the given Arvados collection
+UUID. All new local files will be uploaded.
+""")
+
upload_opts.add_argument('--use-filename', type=str, default=None,
dest='filename', help="""
Synonym for --filename.
Do not continue interrupted uploads from cached state.
""")
+_group = run_opts.add_mutually_exclusive_group()
+_group.add_argument('--cache', action='store_true', dest='use_cache', default=True,
+ help="""
+Save upload state in a cache file for resuming (default).
+""")
+_group.add_argument('--no-cache', action='store_false', dest='use_cache',
+ help="""
+Do not save upload state in a cache file for resuming.
+""")
+
arg_parser = argparse.ArgumentParser(
description='Copy data from the local filesystem to Keep.',
parents=[upload_opts, run_opts, arv_cmd.retry_opt])
and os.isatty(sys.stderr.fileno())):
args.progress = True
+ # Turn off --resume (default) if --no-cache is used.
+ if not args.use_cache:
+ args.resume = False
+
if args.paths == ['-']:
+ if args.update_collection:
+ arg_parser.error("""
+ --update-collection cannot be used when reading from stdin.
+ """)
args.resume = False
+ args.use_cache = False
if not args.filename:
args.filename = 'stdin'
return args
+
+class CollectionUpdateError(Exception):
+ pass
+
+
class ResumeCacheConflict(Exception):
pass
+class ArvPutArgumentConflict(Exception):
+ pass
+
+
+class ArvPutUploadIsPending(Exception):
+ pass
+
+
+class ArvPutUploadNotPending(Exception):
+ pass
+
+
+class FileUploadList(list):
+ def __init__(self, dry_run=False):
+ list.__init__(self)
+ self.dry_run = dry_run
+
+ def append(self, other):
+ if self.dry_run:
+ raise ArvPutUploadIsPending()
+ super(FileUploadList, self).append(other)
+
+
class ResumeCache(object):
CACHE_DIR = '.cache/arvados/arv-put'
realpaths = sorted(os.path.realpath(path) for path in args.paths)
md5.update('\0'.join(realpaths))
if any(os.path.isdir(path) for path in realpaths):
- md5.update(str(max(args.max_manifest_depth, -1)))
+ md5.update("-1")
elif args.filename:
md5.update(args.filename)
return os.path.join(
'files' : {} # Previous run file list: {path : {size, mtime}}
}
- def __init__(self, paths, resume=True, reporter=None, bytes_expected=None,
- name=None, owner_uuid=None, ensure_unique_name=False,
- num_retries=None, replication_desired=None,
- filename=None, update_time=1.0):
+ def __init__(self, paths, resume=True, use_cache=True, reporter=None,
+ bytes_expected=None, name=None, owner_uuid=None,
+ ensure_unique_name=False, num_retries=None, replication_desired=None,
+ filename=None, update_time=20.0, update_collection=None,
+ logger=logging.getLogger('arvados.arv_put'), dry_run=False):
self.paths = paths
self.resume = resume
+ self.use_cache = use_cache
+ self.update = False
self.reporter = reporter
self.bytes_expected = bytes_expected
self.bytes_written = 0
self._state = None # Previous run state (file list & manifest)
self._current_files = [] # Current run file list
self._cache_file = None
- self._collection = None
self._collection_lock = threading.Lock()
+ self._remote_collection = None # Collection being updated (if asked)
+ self._local_collection = None # Collection from previous run manifest
+ self._file_paths = [] # Files to be updated in remote collection
self._stop_checkpointer = threading.Event()
self._checkpointer = threading.Thread(target=self._update_task)
+ self._checkpointer.daemon = True
self._update_task_time = update_time # How many seconds wait between update runs
- self.logger = logging.getLogger('arvados.arv_put')
+ self._files_to_upload = FileUploadList(dry_run=dry_run)
+ self.logger = logger
+ self.dry_run = dry_run
+
+ if not self.use_cache and self.resume:
+ raise ArvPutArgumentConflict('resume cannot be True when use_cache is False')
+
+ # Check for obvious dry-run responses
+ if self.dry_run and (not self.use_cache or not self.resume):
+ raise ArvPutUploadIsPending()
+
# Load cached data if any and if needed
- self._setup_state()
+ self._setup_state(update_collection)
- def start(self):
+ def start(self, save_collection):
"""
Start supporting thread & file uploading
"""
- self._checkpointer.daemon = True
- self._checkpointer.start()
+ if not self.dry_run:
+ self._checkpointer.start()
try:
for path in self.paths:
# Test for stdin first, in case some file named '-' exist
if path == '-':
+ if self.dry_run:
+ raise ArvPutUploadIsPending()
self._write_stdin(self.filename or 'stdin')
elif os.path.isdir(path):
- self._write_directory_tree(path)
+ # Use absolute paths on cache index so CWD doesn't interfere
+ # with the caching logic.
+ prefixdir = path = os.path.abspath(path)
+ if prefixdir != '/':
+ prefixdir += '/'
+ for root, dirs, files in os.walk(path):
+ # Make os.walk()'s dir traversing order deterministic
+ dirs.sort()
+ files.sort()
+ for f in files:
+ self._check_file(os.path.join(root, f),
+ os.path.join(root[len(prefixdir):], f))
else:
- self._write_file(path, self.filename or os.path.basename(path))
- finally:
- # Stop the thread before doing anything else
- self._stop_checkpointer.set()
- self._checkpointer.join()
- # Commit all & one last _update()
- self.manifest_text()
+ self._check_file(os.path.abspath(path),
+ self.filename or os.path.basename(path))
+ # If dry-mode is on, and got up to this point, then we should notify that
+ # there aren't any file to upload.
+ if self.dry_run:
+ raise ArvPutUploadNotPending()
+ # Remove local_collection's files that don't exist locally anymore, so the
+ # bytes_written count is correct.
+ for f in self.collection_file_paths(self._local_collection,
+ path_prefix=""):
+ if f != 'stdin' and f != self.filename and not f in self._file_paths:
+ self._local_collection.remove(f)
+ # Update bytes_written from current local collection and
+ # report initial progress.
self._update()
- if self.resume:
+ # Actual file upload
+ self._upload_files()
+ finally:
+ if not self.dry_run:
+ # Stop the thread before doing anything else
+ self._stop_checkpointer.set()
+ self._checkpointer.join()
+ # Commit all pending blocks & one last _update()
+ self._local_collection.manifest_text()
+ self._update(final=True)
+ if save_collection:
+ self.save_collection()
+ if self.use_cache:
self._cache_file.close()
- # Correct the final written bytes count
- self.bytes_written -= self.bytes_skipped
def save_collection(self):
- with self._collection_lock:
- self._my_collection().save_new(
+ if self.update:
+ # Check if files should be updated on the remote collection.
+ for fp in self._file_paths:
+ remote_file = self._remote_collection.find(fp)
+ if not remote_file:
+ # File don't exist on remote collection, copy it.
+ self._remote_collection.copy(fp, fp, self._local_collection)
+ elif remote_file != self._local_collection.find(fp):
+ # A different file exist on remote collection, overwrite it.
+ self._remote_collection.copy(fp, fp, self._local_collection, overwrite=True)
+ else:
+ # The file already exist on remote collection, skip it.
+ pass
+ self._remote_collection.save(num_retries=self.num_retries)
+ else:
+ self._local_collection.save_new(
name=self.name, owner_uuid=self.owner_uuid,
ensure_unique_name=self.ensure_unique_name,
num_retries=self.num_retries)
def destroy_cache(self):
- if self.resume:
+ if self.use_cache:
try:
os.unlink(self._cache_filename)
except OSError as error:
while not self._stop_checkpointer.wait(self._update_task_time):
self._update()
- def _update(self):
+ def _update(self, final=False):
"""
Update cached manifest text and report progress.
"""
with self._collection_lock:
- self.bytes_written = self._collection_size(self._my_collection())
- # Update cache, if resume enabled
- if self.resume:
+ self.bytes_written = self._collection_size(self._local_collection)
+ if self.use_cache:
+ # Update cache
with self._state_lock:
- # Get the manifest text without comitting pending blocks
- self._state['manifest'] = self._my_collection()._get_manifest_text(".", strip=False, normalize=False, only_committed=True)
+ if final:
+ self._state['manifest'] = self._local_collection.manifest_text()
+ else:
+ # Get the manifest text without comitting pending blocks
+ self._state['manifest'] = self._local_collection._get_manifest_text(".", strip=False, normalize=False, only_committed=True)
self._save_state()
# Call the reporter, if any
self.report_progress()
if self.reporter is not None:
self.reporter(self.bytes_written, self.bytes_expected)
- def _write_directory_tree(self, path, stream_name="."):
- # TODO: Check what happens when multiple directories are passed as
- # arguments.
- # If the code below is uncommented, integration test
- # test_ArvPutSignedManifest (tests.test_arv_put.ArvPutIntegrationTest)
- # fails, I suppose it is because the manifest_uuid changes because
- # of the dir addition to stream_name.
-
- # if stream_name == '.':
- # stream_name = os.path.join('.', os.path.basename(path))
- for item in os.listdir(path):
- if os.path.isdir(os.path.join(path, item)):
- self._write_directory_tree(os.path.join(path, item),
- os.path.join(stream_name, item))
- else:
- self._write_file(os.path.join(path, item),
- os.path.join(stream_name, item))
-
def _write_stdin(self, filename):
- with self._collection_lock:
- output = self._my_collection().open(filename, 'w')
+ output = self._local_collection.open(filename, 'w')
self._write(sys.stdin, output)
output.close()
- def _write_file(self, source, filename):
+ def _check_file(self, source, filename):
+ """Check if this file needs to be uploaded"""
resume_offset = 0
- if self.resume:
- # Check if file was already uploaded (at least partially)
- with self._collection_lock:
- try:
- file_in_collection = self._my_collection().find(filename)
- except IOError:
- # Not found
- file_in_collection = None
+ should_upload = False
+ new_file_in_cache = False
+ # Record file path for updating the remote collection before exiting
+ self._file_paths.append(filename)
+
+ with self._state_lock:
# If no previous cached data on this file, store it for an eventual
# repeated run.
if source not in self._state['files']:
- with self._state_lock:
- self._state['files'][source] = {
- 'mtime': os.path.getmtime(source),
- 'size' : os.path.getsize(source)
- }
- with self._state_lock:
- cached_file_data = self._state['files'][source]
- # See if this file was already uploaded at least partially
- if file_in_collection:
- if cached_file_data['mtime'] == os.path.getmtime(source) and cached_file_data['size'] == os.path.getsize(source):
- if cached_file_data['size'] == file_in_collection.size():
- # File already there, skip it.
- self.bytes_skipped += cached_file_data['size']
- return
- elif cached_file_data['size'] > file_in_collection.size():
- # File partially uploaded, resume!
- resume_offset = file_in_collection.size()
- else:
- # Inconsistent cache, re-upload the file
- self.logger.warning("Uploaded version of file '{}' is bigger than local version, will re-upload it from scratch.".format(source))
- else:
- # Local file differs from cached data, re-upload it
- pass
- with open(source, 'r') as source_fd:
- if resume_offset > 0:
- # Start upload where we left off
- with self._collection_lock:
- output = self._my_collection().open(filename, 'a')
- source_fd.seek(resume_offset)
+ self._state['files'][source] = {
+ 'mtime': os.path.getmtime(source),
+ 'size' : os.path.getsize(source)
+ }
+ new_file_in_cache = True
+ cached_file_data = self._state['files'][source]
+
+ # Check if file was already uploaded (at least partially)
+ file_in_local_collection = self._local_collection.find(filename)
+
+ # If not resuming, upload the full file.
+ if not self.resume:
+ should_upload = True
+ # New file detected from last run, upload it.
+ elif new_file_in_cache:
+ should_upload = True
+ # Local file didn't change from last run.
+ elif cached_file_data['mtime'] == os.path.getmtime(source) and cached_file_data['size'] == os.path.getsize(source):
+ if not file_in_local_collection:
+ # File not uploaded yet, upload it completely
+ should_upload = True
+ elif file_in_local_collection.permission_expired():
+ # Permission token expired, re-upload file. This will change whenever
+ # we have a API for refreshing tokens.
+ should_upload = True
+ self._local_collection.remove(filename)
+ elif cached_file_data['size'] == file_in_local_collection.size():
+ # File already there, skip it.
+ self.bytes_skipped += cached_file_data['size']
+ elif cached_file_data['size'] > file_in_local_collection.size():
+ # File partially uploaded, resume!
+ resume_offset = file_in_local_collection.size()
self.bytes_skipped += resume_offset
+ should_upload = True
else:
- # Start from scratch
- with self._collection_lock:
- output = self._my_collection().open(filename, 'w')
- self._write(source_fd, output)
- output.close(flush=False)
+ # Inconsistent cache, re-upload the file
+ should_upload = True
+ self._local_collection.remove(filename)
+ self.logger.warning("Uploaded version of file '{}' is bigger than local version, will re-upload it from scratch.".format(source))
+ # Local file differs from cached data, re-upload it.
+ else:
+ if file_in_local_collection:
+ self._local_collection.remove(filename)
+ should_upload = True
+
+ if should_upload:
+ self._files_to_upload.append((source, resume_offset, filename))
+
+ def _upload_files(self):
+ for source, resume_offset, filename in self._files_to_upload:
+ with open(source, 'r') as source_fd:
+ with self._state_lock:
+ self._state['files'][source]['mtime'] = os.path.getmtime(source)
+ self._state['files'][source]['size'] = os.path.getsize(source)
+ if resume_offset > 0:
+ # Start upload where we left off
+ output = self._local_collection.open(filename, 'a')
+ source_fd.seek(resume_offset)
+ else:
+ # Start from scratch
+ output = self._local_collection.open(filename, 'w')
+ self._write(source_fd, output)
+ output.close(flush=False)
def _write(self, source_fd, output):
- first_read = True
while True:
data = source_fd.read(arvados.config.KEEP_BLOCK_SIZE)
- # Allow an empty file to be written
- if not data and not first_read:
+ if not data:
break
- if first_read:
- first_read = False
output.write(data)
def _my_collection(self):
- """
- Create a new collection if none cached. Load it from cache otherwise.
- """
- if self._collection is None:
- with self._state_lock:
- manifest = self._state['manifest']
- if self.resume and manifest is not None:
- # Create collection from saved state
- self._collection = arvados.collection.Collection(
- manifest,
- replication_desired=self.replication_desired)
- else:
- # Create new collection
- self._collection = arvados.collection.Collection(
- replication_desired=self.replication_desired)
- return self._collection
+ return self._remote_collection if self.update else self._local_collection
- def _setup_state(self):
+ def _setup_state(self, update_collection):
"""
Create a new cache file or load a previously existing one.
"""
- if self.resume:
+ # Load an already existing collection for update
+ if update_collection and re.match(arvados.util.collection_uuid_pattern,
+ update_collection):
+ try:
+ self._remote_collection = arvados.collection.Collection(update_collection)
+ except arvados.errors.ApiError as error:
+ raise CollectionUpdateError("Cannot read collection {} ({})".format(update_collection, error))
+ else:
+ self.update = True
+ elif update_collection:
+ # Collection locator provided, but unknown format
+ raise CollectionUpdateError("Collection locator unknown: '{}'".format(update_collection))
+
+ if self.use_cache:
+ # Set up cache file name from input paths.
md5 = hashlib.md5()
md5.update(arvados.config.get('ARVADOS_API_HOST', '!nohost'))
realpaths = sorted(os.path.realpath(path) for path in self.paths)
if self.filename:
md5.update(self.filename)
cache_filename = md5.hexdigest()
- self._cache_file = open(os.path.join(
+ cache_filepath = os.path.join(
arv_cmd.make_home_conf_dir(self.CACHE_DIR, 0o700, 'raise'),
- cache_filename), 'a+')
+ cache_filename)
+ if self.resume:
+ self._cache_file = open(cache_filepath, 'a+')
+ else:
+ # --no-resume means start with a empty cache file.
+ self._cache_file = open(cache_filepath, 'w+')
self._cache_filename = self._cache_file.name
self._lock_file(self._cache_file)
self._cache_file.seek(0)
- with self._state_lock:
+
+ with self._state_lock:
+ if self.use_cache:
try:
self._state = json.load(self._cache_file)
if not set(['manifest', 'files']).issubset(set(self._state.keys())):
except ValueError:
# Cache file empty, set up new cache
self._state = copy.deepcopy(self.EMPTY_STATE)
- # Load how many bytes were uploaded on previous run
- with self._collection_lock:
- self.bytes_written = self._collection_size(self._my_collection())
- # No resume required
- else:
- with self._state_lock:
+ else:
+ # No cache file, set empty state
self._state = copy.deepcopy(self.EMPTY_STATE)
+ # Load the previous manifest so we can check if files were modified remotely.
+ self._local_collection = arvados.collection.Collection(self._state['manifest'], replication_desired=self.replication_desired)
+
+ def collection_file_paths(self, col, path_prefix='.'):
+ """Return a list of file paths by recursively go through the entire collection `col`"""
+ file_paths = []
+ for name, item in col.items():
+ if isinstance(item, arvados.arvfile.ArvadosFile):
+ file_paths.append(os.path.join(path_prefix, name))
+ elif isinstance(item, arvados.collection.Subcollection):
+ new_prefix = os.path.join(path_prefix, name)
+ file_paths += self.collection_file_paths(item, path_prefix=new_prefix)
+ return file_paths
def _lock_file(self, fileobj):
try:
"""
try:
with self._state_lock:
- state = self._state
+ state = copy.deepcopy(self._state)
new_cache_fd, new_cache_name = tempfile.mkstemp(
dir=os.path.dirname(self._cache_filename))
self._lock_file(new_cache_fd)
self._cache_file = new_cache
def collection_name(self):
- with self._collection_lock:
- name = self._my_collection().api_response()['name'] if self._my_collection().api_response() else None
- return name
+ return self._my_collection().api_response()['name'] if self._my_collection().api_response() else None
def manifest_locator(self):
- with self._collection_lock:
- locator = self._my_collection().manifest_locator()
- return locator
+ return self._my_collection().manifest_locator()
def portable_data_hash(self):
- with self._collection_lock:
- datahash = self._my_collection().portable_data_hash()
- return datahash
+ return self._my_collection().portable_data_hash()
def manifest_text(self, stream_name=".", strip=False, normalize=False):
- with self._collection_lock:
- manifest = self._my_collection().manifest_text(stream_name, strip, normalize)
- return manifest
+ return self._my_collection().manifest_text(stream_name, strip, normalize)
def _datablocks_on_item(self, item):
"""
def main(arguments=None, stdout=sys.stdout, stderr=sys.stderr):
global api_client
+ logger = logging.getLogger('arvados.arv_put')
args = parse_arguments(arguments)
status = 0
if api_client is None:
# Determine the name to use
if args.name:
if args.stream or args.raw:
- print >>stderr, "Cannot use --name with --stream or --raw"
+ logger.error("Cannot use --name with --stream or --raw")
+ sys.exit(1)
+ elif args.update_collection:
+ logger.error("Cannot use --name with --update-collection")
sys.exit(1)
collection_name = args.name
else:
socket.gethostname())
if args.project_uuid and (args.stream or args.raw):
- print >>stderr, "Cannot use --project-uuid with --stream or --raw"
+ logger.error("Cannot use --project-uuid with --stream or --raw")
sys.exit(1)
# Determine the parent project
project_uuid = desired_project_uuid(api_client, args.project_uuid,
args.retries)
except (apiclient_errors.Error, ValueError) as error:
- print >>stderr, error
+ logger.error(error)
sys.exit(1)
if args.progress:
reporter = None
bytes_expected = expected_bytes_for(args.paths)
+
try:
writer = ArvPutUploadJob(paths = args.paths,
resume = args.resume,
+ use_cache = args.use_cache,
filename = args.filename,
reporter = reporter,
bytes_expected = bytes_expected,
replication_desired = args.replication,
name = collection_name,
owner_uuid = project_uuid,
- ensure_unique_name = True)
+ ensure_unique_name = True,
+ update_collection = args.update_collection,
+ logger=logger,
+ dry_run=args.dry_run)
except ResumeCacheConflict:
- print >>stderr, "\n".join([
+ logger.error("\n".join([
"arv-put: Another process is already uploading this data.",
- " Use --no-resume if this is really what you want."])
+ " Use --no-cache if this is really what you want."]))
sys.exit(1)
+ except CollectionUpdateError as error:
+ logger.error("\n".join([
+ "arv-put: %s" % str(error)]))
+ sys.exit(1)
+ except ArvPutUploadIsPending:
+ # Dry run check successful, return proper exit code.
+ sys.exit(2)
+ except ArvPutUploadNotPending:
+ # No files pending for upload
+ sys.exit(0)
# Install our signal handler for each code in CAUGHT_SIGNALS, and save
# the originals.
orig_signal_handlers = {sigcode: signal.signal(sigcode, exit_signal_handler)
for sigcode in CAUGHT_SIGNALS}
- if args.resume and writer.bytes_written > 0:
- print >>stderr, "\n".join([
- "arv-put: Resuming previous upload from last checkpoint.",
- " Use the --no-resume option to start over."])
+ if not args.dry_run and not args.update_collection and args.resume and writer.bytes_written > 0:
+ logger.warning("\n".join([
+ "arv-put: Resuming previous upload from last checkpoint.",
+ " Use the --no-resume option to start over."]))
- writer.report_progress()
+ if not args.dry_run:
+ writer.report_progress()
output = None
- writer.start()
+ try:
+ writer.start(save_collection=not(args.stream or args.raw))
+ except arvados.errors.ApiError as error:
+ logger.error("\n".join([
+ "arv-put: %s" % str(error)]))
+ sys.exit(1)
+ except ArvPutUploadIsPending:
+ # Dry run check successful, return proper exit code.
+ sys.exit(2)
+ except ArvPutUploadNotPending:
+ # No files pending for upload
+ sys.exit(0)
+
if args.progress: # Print newline to split stderr from stdout for humans.
- print >>stderr
+ logger.info("\n")
if args.stream:
if args.normalize:
output = ','.join(writer.data_locators())
else:
try:
- writer.save_collection()
- print >>stderr, "Collection saved as '%s'" % writer.collection_name()
+ if args.update_collection:
+ logger.info("Collection updated: '{}'".format(writer.collection_name()))
+ else:
+ logger.info("Collection saved as '{}'".format(writer.collection_name()))
if args.portable_data_hash:
output = writer.portable_data_hash()
else:
output = writer.manifest_locator()
except apiclient_errors.Error as error:
- print >>stderr, (
+ logger.error(
"arv-put: Error creating Collection on project: {}.".format(
error))
status = 1
sys.exit(status)
# Success!
- writer.destroy_cache()
return output
import time
import subprocess
import logging
+import sys
import arvados.commands._util as arv_cmd
+from arvados._version import __version__
+
logger = logging.getLogger('arvados.arv-run')
logger.setLevel(logging.INFO)
arvrun_parser = argparse.ArgumentParser(parents=[arv_cmd.retry_opt])
-arvrun_parser.add_argument('--dry-run', action="store_true", help="Print out the pipeline that would be submitted and exit")
-arvrun_parser.add_argument('--local', action="store_true", help="Run locally using arv-run-pipeline-instance")
-arvrun_parser.add_argument('--docker-image', type=str, help="Docker image to use, otherwise use instance default.")
-arvrun_parser.add_argument('--ignore-rcode', action="store_true", help="Commands that return non-zero return codes should not be considered failed.")
-arvrun_parser.add_argument('--no-reuse', action="store_true", help="Do not reuse past jobs.")
-arvrun_parser.add_argument('--no-wait', action="store_true", help="Do not wait and display logs after submitting command, just exit.")
-arvrun_parser.add_argument('--project-uuid', type=str, help="Parent project of the pipeline")
-arvrun_parser.add_argument('--git-dir', type=str, default="", help="Git repository passed to arv-crunch-job when using --local")
-arvrun_parser.add_argument('--repository', type=str, default="arvados", help="repository field of component, default 'arvados'")
-arvrun_parser.add_argument('--script-version', type=str, default="master", help="script_version field of component, default 'master'")
+arvrun_parser.add_argument('--dry-run', action="store_true",
+ help="Print out the pipeline that would be submitted and exit")
+arvrun_parser.add_argument('--local', action="store_true",
+ help="Run locally using arv-run-pipeline-instance")
+arvrun_parser.add_argument('--docker-image', type=str,
+ help="Docker image to use, otherwise use instance default.")
+arvrun_parser.add_argument('--ignore-rcode', action="store_true",
+ help="Commands that return non-zero return codes should not be considered failed.")
+arvrun_parser.add_argument('--no-reuse', action="store_true",
+ help="Do not reuse past jobs.")
+arvrun_parser.add_argument('--no-wait', action="store_true",
+ help="Do not wait and display logs after submitting command, just exit.")
+arvrun_parser.add_argument('--project-uuid', type=str,
+ help="Parent project of the pipeline")
+arvrun_parser.add_argument('--git-dir', type=str, default="",
+ help="Git repository passed to arv-crunch-job when using --local")
+arvrun_parser.add_argument('--repository', type=str, default="arvados",
+ help="repository field of component, default 'arvados'")
+arvrun_parser.add_argument('--script-version', type=str, default="master",
+ help="script_version field of component, default 'master'")
+arvrun_parser.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
arvrun_parser.add_argument('args', nargs=argparse.REMAINDER)
class ArvFile(object):
collection.start_new_stream(stream)
collection.write_file(f.fn, sp[1])
- exists = api.collections().list(filters=[["owner_uuid", "=", project],
- ["portable_data_hash", "=", collection.portable_data_hash()],
- ["name", "=", name]]).execute(num_retries=num_retries)
+ filters=[["portable_data_hash", "=", collection.portable_data_hash()],
+ ["name", "like", name+"%"]]
+ if project:
+ filters.append(["owner_uuid", "=", project])
+
+ exists = api.collections().list(filters=filters).execute(num_retries=num_retries)
+
if exists["items"]:
item = exists["items"][0]
logger.info("Using collection %s", item["uuid"])
import arvados
import json
from arvados.events import subscribe
+from arvados._version import __version__
import signal
def main(arguments=None):
logger = logging.getLogger('arvados.arv-ws')
parser = argparse.ArgumentParser()
+ parser.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
parser.add_argument('-u', '--uuid', type=str, default="", help="Filter events on object_uuid")
parser.add_argument('-f', '--filters', type=str, default="", help="Arvados query filter to apply to log events (JSON encoded)")
parser.add_argument('-s', '--start-time', type=str, default="", help="Arvados query filter to fetch log events created at or after this time. This will be server time in UTC. Allowed format: YYYY-MM-DD or YYYY-MM-DD hh:mm:ss")
def _get_user_agent(self):
try:
- return self._user_agent_pool.get(False)
+ return self._user_agent_pool.get(block=False)
except Queue.Empty:
return pycurl.Curl()
def _put_user_agent(self, ua):
try:
ua.reset()
- self._user_agent_pool.put(ua, False)
+ self._user_agent_pool.put(ua, block=False)
except:
ua.close()
with self.successful_copies_lock:
self.successful_copies += replicas_nr
self.response = response
+ with self.pending_tries_notification:
+ self.pending_tries_notification.notify_all()
- def write_fail(self, ks, status_code):
+ def write_fail(self, ks):
with self.pending_tries_notification:
self.pending_tries += 1
self.pending_tries_notification.notify()
def pending_copies(self):
with self.successful_copies_lock:
return self.wanted_copies - self.successful_copies
-
-
+
+ def get_next_task(self):
+ with self.pending_tries_notification:
+ while True:
+ if self.pending_copies() < 1:
+ # This notify_all() is unnecessary --
+ # write_success() already called notify_all()
+ # when pending<1 became true, so it's not
+ # possible for any other thread to be in
+ # wait() now -- but it's cheap insurance
+ # against deadlock so we do it anyway:
+ self.pending_tries_notification.notify_all()
+ # Drain the queue and then raise Queue.Empty
+ while True:
+ self.get_nowait()
+ self.task_done()
+ elif self.pending_tries > 0:
+ service, service_root = self.get_nowait()
+ if service.finished():
+ self.task_done()
+ continue
+ self.pending_tries -= 1
+ return service, service_root
+ elif self.empty():
+ self.pending_tries_notification.notify_all()
+ raise Queue.Empty
+ else:
+ self.pending_tries_notification.wait()
+
+
class KeepWriterThreadPool(object):
def __init__(self, data, data_hash, copies, max_service_replicas, timeout=None):
self.total_task_nr = 0
worker.start()
# Wait for finished work
self.queue.join()
- with self.queue.pending_tries_notification:
- self.queue.pending_tries_notification.notify_all()
- for worker in self.workers:
- worker.join()
def response(self):
return self.queue.response
class KeepWriterThread(threading.Thread):
+ TaskFailed = RuntimeError()
+
def __init__(self, queue, data, data_hash, timeout=None):
super(KeepClient.KeepWriterThread, self).__init__()
self.timeout = timeout
self.queue = queue
self.data = data
self.data_hash = data_hash
-
+ self.daemon = True
+
def run(self):
- while not self.queue.empty():
- if self.queue.pending_copies() > 0:
- # Avoid overreplication, wait for some needed re-attempt
- with self.queue.pending_tries_notification:
- if self.queue.pending_tries <= 0:
- self.queue.pending_tries_notification.wait()
- continue # try again when awake
- self.queue.pending_tries -= 1
-
- # Get to work
- try:
- service, service_root = self.queue.get_nowait()
- except Queue.Empty:
- continue
- if service.finished():
- self.queue.task_done()
- continue
- success = bool(service.put(self.data_hash,
- self.data,
- timeout=self.timeout))
- result = service.last_result()
- if success:
- _logger.debug("KeepWriterThread %s succeeded %s+%i %s",
- str(threading.current_thread()),
- self.data_hash,
- len(self.data),
- service_root)
- try:
- replicas_stored = int(result['headers']['x-keep-replicas-stored'])
- except (KeyError, ValueError):
- replicas_stored = 1
-
- self.queue.write_success(result['body'].strip(), replicas_stored)
- else:
- if result.get('status_code', None):
- _logger.debug("Request fail: PUT %s => %s %s",
- self.data_hash,
- result['status_code'],
- result['body'])
- self.queue.write_fail(service, result.get('status_code', None)) # Schedule a re-attempt with next service
- # Mark as done so the queue can be join()ed
- self.queue.task_done()
+ while True:
+ try:
+ service, service_root = self.queue.get_next_task()
+ except Queue.Empty:
+ return
+ try:
+ locator, copies = self.do_task(service, service_root)
+ except Exception as e:
+ if e is not self.TaskFailed:
+ _logger.exception("Exception in KeepWriterThread")
+ self.queue.write_fail(service)
else:
- # Remove the task from the queue anyways
- try:
- self.queue.get_nowait()
- # Mark as done so the queue can be join()ed
- self.queue.task_done()
- except Queue.Empty:
- continue
+ self.queue.write_success(locator, copies)
+ finally:
+ self.queue.task_done()
+
+ def do_task(self, service, service_root):
+ success = bool(service.put(self.data_hash,
+ self.data,
+ timeout=self.timeout))
+ result = service.last_result()
+
+ if not success:
+ if result.get('status_code', None):
+ _logger.debug("Request fail: PUT %s => %s %s",
+ self.data_hash,
+ result['status_code'],
+ result['body'])
+ raise self.TaskFailed
+
+ _logger.debug("KeepWriterThread %s succeeded %s+%i %s",
+ str(threading.current_thread()),
+ self.data_hash,
+ len(self.data),
+ service_root)
+ try:
+ replicas_stored = int(result['headers']['x-keep-replicas-stored'])
+ except (KeyError, ValueError):
+ replicas_stored = 1
+
+ return result['body'].strip(), replicas_stored
def __init__(self, api_client=None, proxy=None,
it returns the value of `fallback` (httplib2's CA certs by default).
"""
for ca_certs_path in [
+ # Arvados specific:
+ '/etc/arvados/ca-certificates.crt',
# Debian:
'/etc/ssl/certs/ca-certificates.crt',
# Red Hat:
import arvados
import arvados.commands._util as arv_cmd
+from arvados._version import __version__
+
logger = logging.getLogger('arvados.arv-get')
def abort(msg, code=1):
parser = argparse.ArgumentParser(
description='Copy data from Keep to a local file or pipe.',
parents=[arv_cmd.retry_opt])
+parser.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
parser.add_argument('locator', type=str,
help="""
Collection locator, optionally with a file path or prefix.
import string
import sys
+import arvados
+from arvados._version import __version__
+
parser = argparse.ArgumentParser(
description='Read manifest on standard input and put normalized manifest on standard output.')
-parser.add_argument('--extract', type=str, help="The file to extract from the input manifest")
-parser.add_argument('--strip', action='store_true', help="Strip authorization tokens")
+parser.add_argument('--extract', type=str,
+ help="The file to extract from the input manifest")
+parser.add_argument('--strip', action='store_true',
+ help="Strip authorization tokens")
+parser.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
args = parser.parse_args()
-import arvados
-
r = sys.stdin.read()
cr = arvados.CollectionReader(r)
install_requires=[
'google-api-python-client==1.4.2',
'oauth2client >=1.4.6, <2',
- 'pyasn1-modules==0.0.5',
'ciso8601',
'httplib2',
'pycurl >=7.19.5.1, <7.21.5',
'python-gflags<3.0',
- 'ws4py'
+ 'setuptools',
+ 'ws4py',
+ 'ruamel.yaml==0.13.7'
],
test_suite='tests',
tests_require=['pbr<1.7.0', 'mock>=1.0', 'PyYAML'],
#!/usr/bin/env python
import arvados
+import contextlib
import errno
import hashlib
import httplib
import pycurl
import Queue
import shutil
+import sys
import tempfile
import unittest
def str_keep_locator(s):
return '{}+{}'.format(hashlib.md5(s).hexdigest(), len(s))
+@contextlib.contextmanager
+def redirected_streams(stdout=None, stderr=None):
+ orig_stdout, sys.stdout = sys.stdout, stdout or sys.stdout
+ orig_stderr, sys.stderr = sys.stderr, stderr or sys.stderr
+ try:
+ yield
+ finally:
+ sys.stdout = orig_stdout
+ sys.stderr = orig_stderr
+
+
class FakeCurl:
@classmethod
def make(cls, code, body='', headers={}):
proxy_redirect //download:{{KEEPWEBPORT}}/ https://$host:{{KEEPWEBDLSSLPORT}}/;
}
}
+ upstream ws {
+ server localhost:{{WSPORT}};
+ }
+ server {
+ listen *:{{WSSPORT}} ssl default_server;
+ server_name ~^(?<request_host>.*)$;
+ ssl_certificate {{SSLCERT}};
+ ssl_certificate_key {{SSLKEY}};
+ location / {
+ proxy_pass http://ws;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $request_host:{{WSPORT}};
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+ }
}
my_api_host = None
_cached_config = {}
+_cached_db_config = {}
def find_server_pid(PID_PATH, wait=10):
now = time.time()
os.makedirs(gitdir)
subprocess.check_output(['tar', '-xC', gitdir, '-f', gittarball])
+ # The nginx proxy isn't listening here yet, but we need to choose
+ # the wss:// port now so we can write the API server config file.
+ wss_port = find_available_port()
+ _setport('wss', wss_port)
+
port = find_available_port()
env = os.environ.copy()
env['RAILS_ENV'] = 'test'
- env['ARVADOS_WEBSOCKETS'] = 'yes'
+ env['ARVADOS_TEST_WSS_PORT'] = str(wss_port)
+ if env.get('ARVADOS_TEST_EXPERIMENTAL_WS'):
+ env.pop('ARVADOS_WEBSOCKETS', None)
+ else:
+ env['ARVADOS_WEBSOCKETS'] = 'yes'
env.pop('ARVADOS_TEST_API_HOST', None)
env.pop('ARVADOS_API_HOST', None)
env.pop('ARVADOS_API_HOST_INSECURE', None)
kill_server_pid(_pidfile('api'))
my_api_host = None
+def run_ws():
+ if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
+ return
+ stop_ws()
+ port = find_available_port()
+ conf = os.path.join(TEST_TMPDIR, 'ws.yml')
+ with open(conf, 'w') as f:
+ f.write("""
+Client:
+ APIHost: {}
+ Insecure: true
+Listen: :{}
+LogLevel: {}
+Postgres:
+ host: {}
+ dbname: {}
+ user: {}
+ password: {}
+ sslmode: require
+ """.format(os.environ['ARVADOS_API_HOST'],
+ port,
+ ('info' if os.environ.get('ARVADOS_DEBUG', '') in ['','0'] else 'debug'),
+ _dbconfig('host'),
+ _dbconfig('database'),
+ _dbconfig('username'),
+ _dbconfig('password')))
+ logf = open(_fifo2stderr('ws'), 'w')
+ ws = subprocess.Popen(
+ ["ws", "-config", conf],
+ stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
+ with open(_pidfile('ws'), 'w') as f:
+ f.write(str(ws.pid))
+ _wait_until_port_listens(port)
+ _setport('ws', port)
+ return port
+
+def stop_ws():
+ if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
+ return
+ kill_server_pid(_pidfile('ws'))
+
def _start_keep(n, keep_args):
keep0 = tempfile.mkdtemp()
port = find_available_port()
def run_nginx():
if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
return
+ stop_nginx()
nginxconf = {}
nginxconf['KEEPWEBPORT'] = _getport('keep-web')
nginxconf['KEEPWEBDLSSLPORT'] = find_available_port()
nginxconf['KEEPPROXYSSLPORT'] = find_available_port()
nginxconf['GITPORT'] = _getport('arv-git-httpd')
nginxconf['GITSSLPORT'] = find_available_port()
+ nginxconf['WSPORT'] = _getport('ws')
+ nginxconf['WSSPORT'] = _getport('wss')
nginxconf['SSLCERT'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.pem')
nginxconf['SSLKEY'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.key')
nginxconf['ACCESSLOG'] = _fifo2stderr('nginx_access_log')
except IOError:
return 9
+def _dbconfig(key):
+ global _cached_db_config
+ if not _cached_db_config:
+ _cached_db_config = yaml.load(open(os.path.join(
+ SERVICES_SRC_DIR, 'api', 'config', 'database.yml')))
+ return _cached_db_config['test'][key]
+
def _apiconfig(key):
+ global _cached_config
if _cached_config:
return _cached_config[key]
def _load(f, required=True):
original environment.
"""
MAIN_SERVER = None
+ WS_SERVER = None
KEEP_SERVER = None
KEEP_PROXY_SERVER = None
KEEP_WEB_SERVER = None
os.environ.pop('ARVADOS_EXTERNAL_CLIENT', None)
for server_kwargs, start_func, stop_func in (
(cls.MAIN_SERVER, run, reset),
+ (cls.WS_SERVER, run_ws, stop_ws),
(cls.KEEP_SERVER, run_keep, stop_keep),
(cls.KEEP_PROXY_SERVER, run_keep_proxy, stop_keep_proxy),
(cls.KEEP_WEB_SERVER, run_keep_web, stop_keep_web)):
if __name__ == "__main__":
actions = [
'start', 'stop',
+ 'start_ws', 'stop_ws',
'start_keep', 'stop_keep',
'start_keep_proxy', 'stop_keep_proxy',
'start_keep-web', 'stop_keep-web',
print(host)
elif args.action == 'stop':
stop(force=('ARVADOS_TEST_API_HOST' not in os.environ))
+ elif args.action == 'start_ws':
+ run_ws()
+ elif args.action == 'stop_ws':
+ stop_ws()
elif args.action == 'start_keep':
run_keep(enforce_permissions=args.keep_enforce_permissions, num_servers=args.num_keep_servers)
elif args.action == 'stop_keep':
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import io
+import os
+import sys
+import tempfile
+import unittest
+
+import arvados.commands.arv_copy as arv_copy
+import arvados_testutil as tutil
+
+class ArvCopyTestCase(unittest.TestCase):
+ def run_copy(self, args):
+ sys.argv = ['arv-copy'] + args
+ return arv_copy.main()
+
+ def test_unsupported_arg(self):
+ with self.assertRaises(SystemExit):
+ self.run_copy(['-x=unknown'])
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with tutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_copy(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import io
+import os
+import sys
+import tempfile
+import unittest
+
+import arvados.commands.keepdocker as arv_keepdocker
+import arvados_testutil as tutil
+
+
+class ArvKeepdockerTestCase(unittest.TestCase):
+ def run_arv_keepdocker(self, args):
+ sys.argv = ['arv-keepdocker'] + args
+ return arv_keepdocker.main()
+
+ def test_unsupported_arg(self):
+ with self.assertRaises(SystemExit):
+ self.run_arv_keepdocker(['-x=unknown'])
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with tutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_arv_keepdocker(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
# -*- coding: utf-8 -*-
import io
+import os
import random
-
+import sys
import mock
+import tempfile
import arvados.errors as arv_error
import arvados.commands.ls as arv_ls
import run_test_server
-from arvados_testutil import str_keep_locator
+from arvados_testutil import str_keep_locator, redirected_streams
class ArvLsTestCase(run_test_server.TestCaseWithServers):
FAKE_UUID = 'zzzzz-4zz18-12345abcde12345'
arv_error.NotFoundError)
self.assertNotEqual(0, self.run_ls([self.FAKE_UUID], api_client))
self.assertNotEqual('', self.stderr.getvalue())
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_ls(['--version'], None)
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import subprocess
+import sys
+import tempfile
+import unittest
+
+
+class ArvNormalizeTestCase(unittest.TestCase):
+ def run_arv_normalize(self, args=[]):
+ p = subprocess.Popen([sys.executable, 'bin/arv-normalize'] + args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ return p.returncode, stdout, stderr
+
+ def test_unsupported_arg(self):
+ returncode, out, err = self.run_arv_normalize(['-x=unknown'])
+ self.assertNotEqual(0, returncode)
+
+ def test_version_argument(self):
+ returncode, out, err = self.run_arv_normalize(['--version'])
+ self.assertEqual(0, returncode)
+ self.assertEqual('', out)
+ self.assertNotEqual('', err)
+ self.assertRegexpMatches(err, "[0-9]+\.[0-9]+\.[0-9]+")
# -*- coding: utf-8 -*-
import apiclient
+import io
import mock
import os
import pwd
[],
['/dev/null'],
['/dev/null', '--filename', 'empty'],
- ['/tmp'],
- ['/tmp', '--max-manifest-depth', '0'],
- ['/tmp', '--max-manifest-depth', '1']
+ ['/tmp']
]
def tearDown(self):
class ArvPutUploadJobTest(run_test_server.TestCaseWithServers,
ArvadosBaseTestCase):
+
def setUp(self):
super(ArvPutUploadJobTest, self).setUp()
run_test_server.authorize_with('active')
def test_writer_works_without_cache(self):
cwriter = arv_put.ArvPutUploadJob(['/dev/null'], resume=False)
- cwriter.start()
+ cwriter.start(save_collection=False)
self.assertEqual(". d41d8cd98f00b204e9800998ecf8427e+0 0:0:null\n", cwriter.manifest_text())
def test_writer_works_with_cache(self):
f.write('foo')
f.flush()
cwriter = arv_put.ArvPutUploadJob([f.name])
- cwriter.start()
- self.assertEqual(3, cwriter.bytes_written)
+ cwriter.start(save_collection=False)
+ self.assertEqual(3, cwriter.bytes_written - cwriter.bytes_skipped)
# Don't destroy the cache, and start another upload
cwriter_new = arv_put.ArvPutUploadJob([f.name])
- cwriter_new.start()
+ cwriter_new.start(save_collection=False)
cwriter_new.destroy_cache()
- self.assertEqual(0, cwriter_new.bytes_written)
+ self.assertEqual(0, cwriter_new.bytes_written - cwriter_new.bytes_skipped)
def make_progress_tester(self):
progression = []
progression, reporter = self.make_progress_tester()
cwriter = arv_put.ArvPutUploadJob([f.name],
reporter=reporter, bytes_expected=expect_count)
- cwriter.start()
+ cwriter.start(save_collection=False)
cwriter.destroy_cache()
self.assertIn((3, expect_count), progression)
def test_writer_upload_directory(self):
cwriter = arv_put.ArvPutUploadJob([self.tempdir])
- cwriter.start()
+ cwriter.start(save_collection=False)
cwriter.destroy_cache()
self.assertEqual(1024*(1+2+3+4+5), cwriter.bytes_written)
writer = arv_put.ArvPutUploadJob([self.large_file_name],
replication_desired=1)
with self.assertRaises(SystemExit):
- writer.start()
- self.assertLess(writer.bytes_written,
- os.path.getsize(self.large_file_name))
+ writer.start(save_collection=False)
+ # Confirm that the file was partially uploaded
+ self.assertGreater(writer.bytes_written, 0)
+ self.assertLess(writer.bytes_written,
+ os.path.getsize(self.large_file_name))
# Retry the upload
writer2 = arv_put.ArvPutUploadJob([self.large_file_name],
replication_desired=1)
- writer2.start()
- self.assertEqual(writer.bytes_written + writer2.bytes_written,
+ writer2.start(save_collection=False)
+ self.assertEqual(writer.bytes_written + writer2.bytes_written - writer2.bytes_skipped,
+ os.path.getsize(self.large_file_name))
+ writer2.destroy_cache()
+
+ def test_no_resume_when_asked(self):
+ def wrapped_write(*args, **kwargs):
+ data = args[1]
+ # Exit only on last block
+ if len(data) < arvados.config.KEEP_BLOCK_SIZE:
+ raise SystemExit("Simulated error")
+ return self.arvfile_write(*args, **kwargs)
+
+ with mock.patch('arvados.arvfile.ArvadosFileWriter.write',
+ autospec=True) as mocked_write:
+ mocked_write.side_effect = wrapped_write
+ writer = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1)
+ with self.assertRaises(SystemExit):
+ writer.start(save_collection=False)
+ # Confirm that the file was partially uploaded
+ self.assertGreater(writer.bytes_written, 0)
+ self.assertLess(writer.bytes_written,
+ os.path.getsize(self.large_file_name))
+ # Retry the upload, this time without resume
+ writer2 = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ resume=False)
+ writer2.start(save_collection=False)
+ self.assertEqual(writer2.bytes_skipped, 0)
+ self.assertEqual(writer2.bytes_written,
os.path.getsize(self.large_file_name))
writer2.destroy_cache()
+ def test_no_resume_when_no_cache(self):
+ def wrapped_write(*args, **kwargs):
+ data = args[1]
+ # Exit only on last block
+ if len(data) < arvados.config.KEEP_BLOCK_SIZE:
+ raise SystemExit("Simulated error")
+ return self.arvfile_write(*args, **kwargs)
+
+ with mock.patch('arvados.arvfile.ArvadosFileWriter.write',
+ autospec=True) as mocked_write:
+ mocked_write.side_effect = wrapped_write
+ writer = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1)
+ with self.assertRaises(SystemExit):
+ writer.start(save_collection=False)
+ # Confirm that the file was partially uploaded
+ self.assertGreater(writer.bytes_written, 0)
+ self.assertLess(writer.bytes_written,
+ os.path.getsize(self.large_file_name))
+ # Retry the upload, this time without cache usage
+ writer2 = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ resume=False,
+ use_cache=False)
+ writer2.start(save_collection=False)
+ self.assertEqual(writer2.bytes_skipped, 0)
+ self.assertEqual(writer2.bytes_written,
+ os.path.getsize(self.large_file_name))
+ writer2.destroy_cache()
+
+
+ def test_dry_run_feature(self):
+ def wrapped_write(*args, **kwargs):
+ data = args[1]
+ # Exit only on last block
+ if len(data) < arvados.config.KEEP_BLOCK_SIZE:
+ raise SystemExit("Simulated error")
+ return self.arvfile_write(*args, **kwargs)
+
+ with mock.patch('arvados.arvfile.ArvadosFileWriter.write',
+ autospec=True) as mocked_write:
+ mocked_write.side_effect = wrapped_write
+ writer = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1)
+ with self.assertRaises(SystemExit):
+ writer.start(save_collection=False)
+ # Confirm that the file was partially uploaded
+ self.assertGreater(writer.bytes_written, 0)
+ self.assertLess(writer.bytes_written,
+ os.path.getsize(self.large_file_name))
+ # Retry the upload using dry_run to check if there is a pending upload
+ writer2 = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ dry_run=True)
+ with self.assertRaises(arv_put.ArvPutUploadIsPending):
+ writer2.start(save_collection=False)
+ # Complete the pending upload
+ writer3 = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1)
+ writer3.start(save_collection=False)
+ # Confirm there's no pending upload with dry_run=True
+ writer4 = arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ dry_run=True)
+ with self.assertRaises(arv_put.ArvPutUploadNotPending):
+ writer4.start(save_collection=False)
+ writer4.destroy_cache()
+ # Test obvious cases
+ with self.assertRaises(arv_put.ArvPutUploadIsPending):
+ arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ dry_run=True,
+ resume=False,
+ use_cache=False)
+ with self.assertRaises(arv_put.ArvPutUploadIsPending):
+ arv_put.ArvPutUploadJob([self.large_file_name],
+ replication_desired=1,
+ dry_run=True,
+ resume=False)
+
class ArvadosExpectedBytesTest(ArvadosBaseTestCase):
TEST_SIZE = os.path.getsize(__file__)
delattr(self, outbuf)
super(ArvadosPutTest, self).tearDown()
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with tutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.call_main_with_args(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
+
def test_simple_file_put(self):
self.call_main_on_test_file()
self.assertEqual(1, len(collection_list))
return collection_list[0]
+ def test_put_collection_with_later_update(self):
+ tmpdir = self.make_tmpdir()
+ with open(os.path.join(tmpdir, 'file1'), 'w') as f:
+ f.write('Relaxing in basins at the end of inlets terminates the endless tests from the box')
+ col = self.run_and_find_collection("", ['--no-progress', tmpdir])
+ self.assertNotEqual(None, col['uuid'])
+ # Add a new file to the directory
+ with open(os.path.join(tmpdir, 'file2'), 'w') as f:
+ f.write('The quick brown fox jumped over the lazy dog')
+ updated_col = self.run_and_find_collection("", ['--no-progress', '--update-collection', col['uuid'], tmpdir])
+ self.assertEqual(col['uuid'], updated_col['uuid'])
+ # Get the manifest and check that the new file is being included
+ c = arv_put.api_client.collections().get(uuid=updated_col['uuid']).execute()
+ self.assertRegexpMatches(c['manifest_text'], r'^\. .*:44:file2\n')
+
def test_put_collection_with_high_redundancy(self):
# Write empty data: we're not testing CollectionWriter, just
# making sure collections.create tells the API server what our
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import io
+import os
+import sys
+import tempfile
+import unittest
+
+import arvados.commands.run as arv_run
+import arvados_testutil as tutil
+
+class ArvRunTestCase(unittest.TestCase):
+ def run_arv_run(self, args):
+ sys.argv = ['arv-run'] + args
+ return arv_run.main()
+
+ def test_unsupported_arg(self):
+ with self.assertRaises(SystemExit):
+ self.run_arv_run(['-x=unknown'])
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with tutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_arv_run(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
#!/usr/bin/env python
+import io
+import os
+import sys
+import tempfile
import unittest
+
import arvados.errors as arv_error
import arvados.commands.ws as arv_ws
+import arvados_testutil as tutil
class ArvWsTestCase(unittest.TestCase):
def run_ws(self, args):
def test_unsupported_arg(self):
with self.assertRaises(SystemExit):
self.run_ws(['-x=unknown'])
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with tutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_ws(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
#!/usr/bin/env python
import bz2
+import datetime
import gzip
import io
import mock
def read_for_test(self, reader, byte_count, **kwargs):
return ''.join(reader.readlines(**kwargs))
+
+class ArvadosFileTestCase(unittest.TestCase):
+ def datetime_to_hex(self, dt):
+ return hex(int(time.mktime(dt.timetuple())))[2:]
+
+ def test_permission_expired(self):
+ base_manifest = ". 781e5e245d69b566979b86e28d23f2c7+10+A715fd31f8111894f717eb1003c1b0216799dd9ec@{} 0:10:count.txt\n"
+ now = datetime.datetime.now()
+ a_week_ago = now - datetime.timedelta(days=7)
+ a_month_ago = now - datetime.timedelta(days=30)
+ a_week_from_now = now + datetime.timedelta(days=7)
+ with Collection(base_manifest.format(self.datetime_to_hex(a_week_from_now))) as c:
+ self.assertFalse(c.find('count.txt').permission_expired())
+ with Collection(base_manifest.format(self.datetime_to_hex(a_week_ago))) as c:
+ f = c.find('count.txt')
+ self.assertTrue(f.permission_expired())
+ self.assertTrue(f.permission_expired(a_week_from_now))
+ self.assertFalse(f.permission_expired(a_month_ago))
+
+
class BlockManagerTest(unittest.TestCase):
def test_bufferblock_append(self):
keep = ArvadosFileWriterTestCase.MockKeep({})
c.find("/.")
with self.assertRaises(arvados.errors.ArgumentError):
c.find("")
+ self.assertIs(c.find("./nonexistant.txt"), None)
+ self.assertIs(c.find("./nonexistantsubdir/nonexistant.txt"), None)
def test_remove_in_subdir(self):
c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
TIME_FUTURE = time.time()+3600
MOCK_WS_URL = 'wss://[{}]/'.format(arvados_testutil.TEST_HOST)
+ TEST_TIMEOUT = 10.0
+
def setUp(self):
self.ws = None
self.assertEqual(200, events.get(True, 5)['status'])
human = arvados.api('v1').humans().create(body={}).execute()
- log_object_uuids = []
- for i in range(0, expected):
- log_object_uuids.append(events.get(True, 5)['object_uuid'])
-
+ want_uuids = []
if expected > 0:
- self.assertIn(human['uuid'], log_object_uuids)
-
+ want_uuids.append(human['uuid'])
if expected > 1:
- self.assertIn(ancestor['uuid'], log_object_uuids)
+ want_uuids.append(ancestor['uuid'])
+ log_object_uuids = []
+ while set(want_uuids) - set(log_object_uuids):
+ log_object_uuids.append(events.get(True, 5)['object_uuid'])
- with self.assertRaises(Queue.Empty):
- # assertEqual just serves to show us what unexpected thing
- # comes out of the queue when the assertRaises fails; when
- # the test passes, this assertEqual doesn't get called.
- self.assertEqual(events.get(True, 2), None)
+ if expected < 2:
+ with self.assertRaises(Queue.Empty):
+ # assertEqual just serves to show us what unexpected
+ # thing comes out of the queue when the assertRaises
+ # fails; when the test passes, this assertEqual
+ # doesn't get called.
+ self.assertEqual(events.get(True, 2), None)
def test_subscribe_websocket(self):
self._test_subscribe(
return time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t)) + self.isotz(-time.timezone/60)
def isotz(self, offset):
- """Convert minutes-east-of-UTC to ISO8601 time zone designator"""
- return '{:+03d}{:02d}'.format(offset/60, offset%60)
+ """Convert minutes-east-of-UTC to RFC3339- and ISO-compatible time zone designator"""
+ return '{:+03d}:{:02d}'.format(offset/60, offset%60)
# Test websocket reconnection on (un)execpted close
def _test_websocket_reconnect(self, close_unexpected):
@mock.patch('arvados.events._EventClient')
def test_run_forever_survives_reconnects(self, websocket_client):
- connection_cond = threading.Condition()
- def ws_connect():
- with connection_cond:
- connection_cond.notify_all()
- websocket_client().connect.side_effect = ws_connect
+ connected = threading.Event()
+ websocket_client().connect.side_effect = connected.set
client = arvados.events.EventClient(
self.MOCK_WS_URL, [], lambda event: None, None)
- with connection_cond:
- forever_thread = threading.Thread(target=client.run_forever)
- forever_thread.start()
- # Simulate an unexpected disconnect, and wait for reconnect.
- close_thread = threading.Thread(target=client.on_closed)
- close_thread.start()
- connection_cond.wait()
+ forever_thread = threading.Thread(target=client.run_forever)
+ forever_thread.start()
+ # Simulate an unexpected disconnect, and wait for reconnect.
+ close_thread = threading.Thread(target=client.on_closed)
+ close_thread.start()
+ self.assertTrue(connected.wait(timeout=self.TEST_TIMEOUT))
close_thread.join()
run_forever_alive = forever_thread.is_alive()
client.close()
class PollClientTestCase(unittest.TestCase):
+ TEST_TIMEOUT = 10.0
+
class MockLogs(object):
+
def __init__(self):
self.logs = []
self.lock = threading.Lock()
+ self.api_called = threading.Event()
def add(self, log):
with self.lock:
self.logs.append(log)
def return_list(self, num_retries=None):
+ self.api_called.set()
+ args, kwargs = self.list_func.call_args_list[-1]
+ filters = kwargs.get('filters', [])
+ if not any(True for f in filters if f[0] == 'id' and f[1] == '>'):
+ # No 'id' filter was given -- this must be the probe
+ # to determine the most recent id.
+ return {'items': [{'id': 1}], 'items_available': 1}
with self.lock:
retval = self.logs
self.logs = []
return {'items': retval, 'items_available': len(retval)}
-
def setUp(self):
self.logs = self.MockLogs()
self.arv = mock.MagicMock(name='arvados.api()')
self.arv.logs().list().execute.side_effect = self.logs.return_list
- self.callback_cond = threading.Condition()
+ # our MockLogs object's "execute" stub will need to inspect
+ # the call history to determine X in
+ # ....logs().list(filters=X).execute():
+ self.logs.list_func = self.arv.logs().list
+ self.status_ok = threading.Event()
+ self.event_received = threading.Event()
self.recv_events = []
def tearDown(self):
self.client.close(timeout=None)
def callback(self, event):
- with self.callback_cond:
+ if event.get('status') == 200:
+ self.status_ok.set()
+ else:
self.recv_events.append(event)
- self.callback_cond.notify_all()
+ self.event_received.set()
def build_client(self, filters=None, callback=None, last_log_id=None, poll_time=99):
if filters is None:
test_log = {'id': 12345, 'testkey': 'testtext'}
self.logs.add({'id': 123})
self.build_client(poll_time=.01)
- with self.callback_cond:
- self.client.start()
- self.callback_cond.wait()
- self.logs.add(test_log.copy())
- self.callback_cond.wait()
- self.client.close(timeout=None)
+ self.client.start()
+ self.assertTrue(self.status_ok.wait(self.TEST_TIMEOUT))
+ self.assertTrue(self.event_received.wait(self.TEST_TIMEOUT))
+ self.event_received.clear()
+ self.logs.add(test_log.copy())
+ self.assertTrue(self.event_received.wait(self.TEST_TIMEOUT))
self.assertIn(test_log, self.recv_events)
def test_subscribe(self):
client_filter = ['kind', '=', 'arvados#test']
self.build_client()
+ self.client.unsubscribe([])
self.client.subscribe([client_filter[:]])
- with self.callback_cond:
- self.client.start()
- self.callback_cond.wait()
- self.client.close(timeout=None)
+ self.client.start()
+ self.assertTrue(self.status_ok.wait(self.TEST_TIMEOUT))
+ self.assertTrue(self.logs.api_called.wait(self.TEST_TIMEOUT))
self.assertTrue(self.was_filter_used(client_filter))
def test_unsubscribe(self):
- client_filter = ['kind', '=', 'arvados#test']
- self.build_client()
- self.client.subscribe([client_filter[:]])
- self.client.unsubscribe([client_filter[:]])
+ should_filter = ['foo', '=', 'foo']
+ should_not_filter = ['foo', '=', 'bar']
+ self.build_client(poll_time=0.01)
+ self.client.unsubscribe([])
+ self.client.subscribe([should_not_filter[:]])
+ self.client.subscribe([should_filter[:]])
+ self.client.unsubscribe([should_not_filter[:]])
self.client.start()
- self.client.close(timeout=None)
- self.assertFalse(self.was_filter_used(client_filter))
+ self.logs.add({'id': 123})
+ self.assertTrue(self.status_ok.wait(self.TEST_TIMEOUT))
+ self.assertTrue(self.event_received.wait(self.TEST_TIMEOUT))
+ self.assertTrue(self.was_filter_used(should_filter))
+ self.assertFalse(self.was_filter_used(should_not_filter))
def test_run_forever(self):
self.build_client()
- with self.callback_cond:
- self.client.start()
- forever_thread = threading.Thread(target=self.client.run_forever)
- forever_thread.start()
- self.callback_cond.wait()
+ self.client.start()
+ forever_thread = threading.Thread(target=self.client.run_forever)
+ forever_thread.start()
+ self.assertTrue(self.status_ok.wait(self.TEST_TIMEOUT))
self.assertTrue(forever_thread.is_alive())
self.client.close()
forever_thread.join()
+ del self.client
self.check_exception(copies=2, num_retries=3)
-class KeepClientAvoidClientOverreplicationTestCase(unittest.TestCase, tutil.ApiClientMock):
-
-
+class AvoidOverreplication(unittest.TestCase, tutil.ApiClientMock):
+
class FakeKeepService(object):
- def __init__(self, delay, will_succeed, replicas=1):
+ def __init__(self, delay, will_succeed=False, will_raise=None, replicas=1):
self.delay = delay
- self.success = will_succeed
+ self.will_succeed = will_succeed
+ self.will_raise = will_raise
self._result = {}
self._result['headers'] = {}
self._result['headers']['x-keep-replicas-stored'] = str(replicas)
self._result['body'] = 'foobar'
-
+
def put(self, data_hash, data, timeout):
time.sleep(self.delay)
- return self.success
-
+ if self.will_raise is not None:
+ raise self.will_raise
+ return self.will_succeed
+
def last_result(self):
- return self._result
-
+ if self.will_succeed:
+ return self._result
+
def finished(self):
return False
-
- def test_only_write_enough_on_success(self):
- copies = 3
- pool = arvados.KeepClient.KeepWriterThreadPool(
+ def setUp(self):
+ self.copies = 3
+ self.pool = arvados.KeepClient.KeepWriterThreadPool(
data = 'foo',
data_hash = 'acbd18db4cc2f85cedef654fccc4a4d8+3',
- max_service_replicas = copies,
- copies = copies
+ max_service_replicas = self.copies,
+ copies = self.copies
)
+
+ def test_only_write_enough_on_success(self):
for i in range(10):
ks = self.FakeKeepService(delay=i/10.0, will_succeed=True)
- pool.add_task(ks, None)
- pool.join()
- self.assertEqual(pool.done(), copies)
+ self.pool.add_task(ks, None)
+ self.pool.join()
+ self.assertEqual(self.pool.done(), self.copies)
def test_only_write_enough_on_partial_success(self):
- copies = 3
- pool = arvados.KeepClient.KeepWriterThreadPool(
- data = 'foo',
- data_hash = 'acbd18db4cc2f85cedef654fccc4a4d8+3',
- max_service_replicas = copies,
- copies = copies
- )
for i in range(5):
ks = self.FakeKeepService(delay=i/10.0, will_succeed=False)
- pool.add_task(ks, None)
+ self.pool.add_task(ks, None)
+ ks = self.FakeKeepService(delay=i/10.0, will_succeed=True)
+ self.pool.add_task(ks, None)
+ self.pool.join()
+ self.assertEqual(self.pool.done(), self.copies)
+
+ def test_only_write_enough_when_some_crash(self):
+ for i in range(5):
+ ks = self.FakeKeepService(delay=i/10.0, will_raise=Exception())
+ self.pool.add_task(ks, None)
+ ks = self.FakeKeepService(delay=i/10.0, will_succeed=True)
+ self.pool.add_task(ks, None)
+ self.pool.join()
+ self.assertEqual(self.pool.done(), self.copies)
+
+ def test_fail_when_too_many_crash(self):
+ for i in range(self.copies+1):
+ ks = self.FakeKeepService(delay=i/10.0, will_raise=Exception())
+ self.pool.add_task(ks, None)
+ for i in range(self.copies-1):
ks = self.FakeKeepService(delay=i/10.0, will_succeed=True)
- pool.add_task(ks, None)
- pool.join()
- self.assertEqual(pool.done(), copies)
+ self.pool.add_task(ks, None)
+ self.pool.join()
+ self.assertEqual(self.pool.done(), self.copies-1)
@tutil.skip_sleep
source 'https://rubygems.org'
-gem 'rails', '~> 3.2.0'
+gem 'rails', '~> 3.2'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
# Note: "require: false" here tells bunder not to automatically
# 'require' the packages during application startup. Installation is
# still mandatory.
+ gem 'test-unit', '~> 3.0', require: false
gem 'simplecov', '~> 0.7.1', require: false
gem 'simplecov-rcov', require: false
gem 'mocha', require: false
end
-# This might not be needed in :test and :development, but we load it
-# anyway to make sure it always gets in Gemfile.lock and to help
-# reveal install problems sooner rather than later.
+# pg is the only supported database driver.
gem 'pg'
# Start using multi_json once we are on Rails 3.2;
# Gems used only for assets and not required
# in production environments by default.
group :assets do
- gem 'sass-rails', '>= 3.2.0'
- gem 'coffee-rails', '~> 3.2.0'
+ gem 'sass-rails', '~> 3.2'
+ gem 'coffee-rails', '~> 3.2'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer'
- gem 'uglifier', '>= 1.0.3'
+ gem 'uglifier', '~> 2.0'
end
gem 'jquery-rails'
gem 'passenger'
-gem 'omniauth', '1.1.1'
-gem 'omniauth-oauth2', '1.1.1'
+gem 'omniauth', '~> 1.1'
+gem 'omniauth-oauth2', '~> 1.1'
gem 'andand'
# pg_power lets us use partial indexes in schema.rb in Rails 3
gem 'pg_power'
-gem 'puma'
+gem 'puma', '~> 2.0'
gem 'sshkey'
gem 'safe_yaml'
gem 'lograge'
gem 'logstash-event'
+
+# Install any plugin gems
+Dir.glob(File.join(File.dirname(__FILE__), 'lib', '**', "Gemfile")) do |gemfile|
+ eval(IO.read(gemfile), binding)
+end
GEM
remote: https://rubygems.org/
specs:
- actionmailer (3.2.17)
- actionpack (= 3.2.17)
+ actionmailer (3.2.22.5)
+ actionpack (= 3.2.22.5)
mail (~> 2.5.4)
- actionpack (3.2.17)
- activemodel (= 3.2.17)
- activesupport (= 3.2.17)
+ actionpack (3.2.22.5)
+ activemodel (= 3.2.22.5)
+ activesupport (= 3.2.22.5)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
- activemodel (3.2.17)
- activesupport (= 3.2.17)
+ activemodel (3.2.22.5)
+ activesupport (= 3.2.22.5)
builder (~> 3.0.0)
- activerecord (3.2.17)
- activemodel (= 3.2.17)
- activesupport (= 3.2.17)
+ activerecord (3.2.22.5)
+ activemodel (= 3.2.22.5)
+ activesupport (= 3.2.22.5)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
- activeresource (3.2.17)
- activemodel (= 3.2.17)
- activesupport (= 3.2.17)
- activesupport (3.2.17)
+ activeresource (3.2.22.5)
+ activemodel (= 3.2.22.5)
+ activesupport (= 3.2.22.5)
+ activesupport (3.2.22.5)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
- acts_as_api (0.4.2)
+ acts_as_api (0.4.3)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
rack (>= 1.1.0)
addressable (2.4.0)
andand (1.3.3)
arel (3.0.3)
- arvados (0.1.20160420143004)
+ arvados (0.1.20160513152536)
activesupport (>= 3, < 4.2.6)
andand (~> 1.3, >= 1.3.3)
- google-api-client (>= 0.7, < 0.9)
+ google-api-client (>= 0.7, < 0.8.9)
i18n (~> 0)
json (~> 1.7, >= 1.7.7)
jwt (>= 0.1.5, < 2)
extlib (>= 0.9.15)
multi_json (>= 1.0.0)
builder (3.0.4)
- capistrano (2.15.5)
+ capistrano (2.15.9)
highline
net-scp (>= 1.0.0)
net-sftp (>= 2.0.0)
net-ssh (>= 2.0.14)
net-ssh-gateway (>= 1.1.0)
- coffee-rails (3.2.1)
+ coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
- railties (~> 3.2.0.beta)
- coffee-script (2.2.0)
+ railties (~> 3.2.0)
+ coffee-script (2.4.1)
coffee-script-source
execjs
- coffee-script-source (1.7.0)
+ coffee-script-source (1.10.0)
curb (0.9.3)
- daemon_controller (1.2.0)
- database_cleaner (1.2.0)
+ database_cleaner (1.5.3)
erubis (2.7.0)
- eventmachine (1.0.3)
- execjs (2.0.2)
+ eventmachine (1.2.0.1)
+ execjs (2.7.0)
extlib (0.9.16)
- factory_girl (4.4.0)
+ factory_girl (4.7.0)
activesupport (>= 3.0.0)
- factory_girl_rails (4.4.1)
- factory_girl (~> 4.4.0)
+ factory_girl_rails (4.7.0)
+ factory_girl (~> 4.7.0)
railties (>= 3.0.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- faye-websocket (0.7.2)
+ faye-websocket (0.10.4)
eventmachine (>= 0.12.0)
- websocket-driver (>= 0.3.1)
- google-api-client (0.7.1)
- addressable (>= 2.3.2)
- autoparse (>= 0.3.3)
- extlib (>= 0.9.15)
- faraday (>= 0.9.0)
- jwt (>= 0.1.5)
- launchy (>= 2.1.1)
- multi_json (>= 1.0.0)
- retriable (>= 1.4)
- signet (>= 0.5.0)
- uuidtools (>= 2.1.0)
- hashie (1.2.0)
- highline (1.6.21)
+ websocket-driver (>= 0.5.1)
+ google-api-client (0.8.7)
+ activesupport (>= 3.2, < 5.0)
+ addressable (~> 2.3)
+ autoparse (~> 0.3)
+ extlib (~> 0.9)
+ faraday (~> 0.9)
+ googleauth (~> 0.3)
+ launchy (~> 2.4)
+ multi_json (~> 1.10)
+ retriable (~> 1.4)
+ signet (~> 0.6)
+ googleauth (0.5.1)
+ faraday (~> 0.9)
+ jwt (~> 1.4)
+ logging (~> 2.0)
+ memoist (~> 0.12)
+ multi_json (~> 1.11)
+ os (~> 0.9)
+ signet (~> 0.7)
+ hashie (3.4.6)
+ highline (1.7.8)
hike (1.2.3)
- httpauth (0.2.1)
i18n (0.7.0)
journey (1.0.4)
- jquery-rails (3.1.0)
+ jquery-rails (3.1.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
- jwt (0.1.13)
- multi_json (>= 1.5)
+ jwt (1.5.6)
launchy (2.4.3)
addressable (~> 2.3)
- libv8 (3.16.14.3)
+ libv8 (3.16.14.15)
+ little-plugger (1.1.4)
+ logging (2.1.0)
+ little-plugger (~> 1.1)
+ multi_json (~> 1.10)
lograge (0.3.6)
actionpack (>= 3)
activesupport (>= 3)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
+ memoist (0.15.0)
metaclass (0.0.4)
mime-types (1.25.1)
- mocha (1.1.0)
+ mocha (1.2.0)
metaclass (~> 0.0.1)
- multi_json (1.12.0)
+ multi_json (1.12.1)
+ multi_xml (0.5.5)
multipart-post (2.0.0)
- net-scp (1.2.0)
+ net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
- net-ssh (2.8.0)
+ net-ssh (3.2.0)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
- oauth2 (0.8.1)
- faraday (~> 0.8)
- httpauth (~> 0.1)
- jwt (~> 0.1.4)
- multi_json (~> 1.0)
- rack (~> 1.2)
+ oauth2 (1.2.0)
+ faraday (>= 0.8, < 0.10)
+ jwt (~> 1.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 3)
oj (2.15.0)
- omniauth (1.1.1)
- hashie (~> 1.2)
- rack
- omniauth-oauth2 (1.1.1)
- oauth2 (~> 0.8.0)
- omniauth (~> 1.0)
- passenger (4.0.41)
- daemon_controller (>= 1.2.0)
+ omniauth (1.3.1)
+ hashie (>= 1.2, < 4)
+ rack (>= 1.0, < 3)
+ omniauth-oauth2 (1.4.0)
+ oauth2 (~> 1.0)
+ omniauth (~> 1.2)
+ os (0.9.6)
+ passenger (5.0.30)
rack
rake (>= 0.8.1)
- pg (0.17.1)
+ pg (0.19.0)
pg_power (1.6.4)
pg
rails (~> 3.1)
- polyglot (0.3.4)
- puma (2.8.2)
- rack (>= 1.1, < 2.0)
- rack (1.4.5)
- rack-cache (1.2)
+ polyglot (0.3.5)
+ power_assert (0.3.1)
+ puma (2.16.0)
+ rack (1.4.7)
+ rack-cache (1.6.1)
rack (>= 0.4)
rack-ssl (1.3.4)
rack
- rack-test (0.6.2)
+ rack-test (0.6.3)
rack (>= 1.0)
- rails (3.2.17)
- actionmailer (= 3.2.17)
- actionpack (= 3.2.17)
- activerecord (= 3.2.17)
- activeresource (= 3.2.17)
- activesupport (= 3.2.17)
+ rails (3.2.22.5)
+ actionmailer (= 3.2.22.5)
+ actionpack (= 3.2.22.5)
+ activerecord (= 3.2.22.5)
+ activeresource (= 3.2.22.5)
+ activesupport (= 3.2.22.5)
bundler (~> 1.0)
- railties (= 3.2.17)
- railties (3.2.17)
- actionpack (= 3.2.17)
- activesupport (= 3.2.17)
+ railties (= 3.2.22.5)
+ railties (3.2.22.5)
+ actionpack (= 3.2.22.5)
+ activesupport (= 3.2.22.5)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
- rake (10.2.2)
+ rake (11.3.0)
rdoc (3.12.2)
json (~> 1.4)
- ref (1.0.5)
- retriable (2.1.0)
- ruby-prof (0.15.2)
- rvm-capistrano (1.5.1)
+ ref (2.0.0)
+ retriable (1.4.1)
+ ruby-prof (0.16.2)
+ rvm-capistrano (1.5.6)
capistrano (~> 2.15.4)
safe_yaml (1.0.4)
- sass (3.3.4)
+ sass (3.4.22)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
- signet (0.5.1)
- addressable (>= 2.2.3)
- faraday (>= 0.9.0.rc5)
- jwt (>= 0.1.5)
- multi_json (>= 1.0.0)
+ signet (0.7.3)
+ addressable (~> 2.3)
+ faraday (~> 0.9)
+ jwt (~> 1.5)
+ multi_json (~> 1.10)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
simplecov-rcov (0.2.3)
simplecov (>= 0.4.1)
- sprockets (2.2.2)
+ sprockets (2.2.3)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
- sshkey (1.6.1)
- test_after_commit (0.2.3)
+ sshkey (1.8.0)
+ test-unit (3.2.1)
+ power_assert
+ test_after_commit (1.1.0)
+ activerecord (>= 3.2)
themes_for_rails (0.5.1)
rails (>= 3.0.0)
- therubyracer (0.12.1)
+ therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
ref
thor (0.19.1)
polyglot
polyglot (>= 0.3.1)
trollop (2.1.2)
- tzinfo (0.3.39)
- uglifier (2.5.0)
+ tzinfo (0.3.51)
+ uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
- uuidtools (2.1.5)
- websocket-driver (0.3.2)
+ websocket-driver (0.6.4)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.2)
PLATFORMS
ruby
andand
arvados (>= 0.1.20150615153458)
arvados-cli (>= 0.1.20161017193526)
- coffee-rails (~> 3.2.0)
+ coffee-rails (~> 3.2)
database_cleaner
factory_girl_rails
faye-websocket
mocha
multi_json
oj
- omniauth (= 1.1.1)
- omniauth-oauth2 (= 1.1.1)
+ omniauth (~> 1.1)
+ omniauth-oauth2 (~> 1.1)
passenger
pg
pg_power
- puma
- rails (~> 3.2.0)
+ puma (~> 2.0)
+ rails (~> 3.2)
ruby-prof
rvm-capistrano
safe_yaml
- sass-rails (>= 3.2.0)
+ sass-rails (~> 3.2)
simplecov (~> 0.7.1)
simplecov-rcov
sshkey
+ test-unit (~> 3.0)
test_after_commit
themes_for_rails
therubyracer
trollop
- uglifier (>= 1.0.3)
+ uglifier (~> 2.0)
+
+BUNDLED WITH
+ 1.13.6
include CurrentApiClient
include ThemesForRails::ActionController
include LoadParam
+ include DbCurrentTime
respond_to :json
protect_from_forgery
theme :select_theme
- attr_accessor :resource_attrs
+ attr_writer :resource_attrs
+
+ MAX_UNIQUE_NAME_ATTEMPTS = 10
begin
rescue_from(Exception,
:with => :render_not_found)
end
+ def initialize *args
+ super
+ @object = nil
+ @objects = nil
+ @offset = nil
+ @limit = nil
+ @select = nil
+ @distinct = nil
+ @response_resource_name = nil
+ @attrs = nil
+ end
+
def default_url_options
if Rails.configuration.host
{:host => Rails.configuration.host}
if @object.respond_to? :name and params[:ensure_unique_name]
# Record the original name. See below.
name_stem = @object.name
- counter = 1
+ retries = MAX_UNIQUE_NAME_ATTEMPTS
+ else
+ retries = 0
end
begin
@object.save!
rescue ActiveRecord::RecordNotUnique => rn
- raise unless params[:ensure_unique_name]
+ raise unless retries > 0
+ retries -= 1
# Dig into the error to determine if it is specifically calling out a
# (owner_uuid, name) uniqueness violation. In this specific case, and
detail = err.result.error_field(PG::Result::PG_DIAG_MESSAGE_DETAIL)
raise unless /^Key \(owner_uuid, name\)=\([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}, .*?\) already exists\./.match detail
- # OK, this exception really is just a unique name constraint
- # violation, and we've been asked to ensure_unique_name.
- counter += 1
@object.uuid = nil
- @object.name = "#{name_stem} (#{counter})"
- redo
- end while false
+
+ new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+ if new_name == @object.name
+ # If the database is fast enough to do two attempts in the
+ # same millisecond, we need to wait to ensure we try a
+ # different timestamp on each attempt.
+ sleep 0.002
+ new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+ end
+ @object.name = new_name
+ retry
+ end
show
end
end
def find_object_by_uuid
- if params[:id] and params[:id].match /\D/
+ if params[:id] and params[:id].match(/\D/)
params[:uuid] = params.delete :id
end
@where = { uuid: params[:uuid] }
}
end
end
- super *opts
+ super(*opts)
end
def select_theme
require "arvados/keep"
class Arvados::V1::CollectionsController < ApplicationController
+ include DbCurrentTime
+
def self.limit_index_columns_read
["manifest_text"]
end
super
end
+ def find_objects_for_index
+ if params[:include_trash] || ['destroy', 'trash'].include?(action_name)
+ @objects = Collection.unscoped.readable_by(*@read_users)
+ end
+ super
+ end
+
def find_object_by_uuid
if loc = Keep::Locator.parse(params[:id])
loc.strip_hints!
manifest_text: c.signed_manifest_text,
}
end
+ true
else
super
end
- true
end
def show
if @object.is_a? Collection
+ # Omit unsigned_manifest_text
+ @select ||= model_class.selectable_attributes - ["unsigned_manifest_text"]
super
else
send_json @object
end
end
+ def destroy
+ if !@object.is_trashed
+ @object.update_attributes!(trash_at: db_current_time)
+ end
+ earliest_delete = (@object.trash_at +
+ Rails.configuration.blob_signature_ttl.seconds)
+ if @object.delete_at > earliest_delete
+ @object.update_attributes!(delete_at: earliest_delete)
+ end
+ show
+ end
+
+ def trash
+ if !@object.is_trashed
+ @object.update_attributes!(trash_at: db_current_time)
+ end
+ show
+ end
+
def find_collections(visited, sp, &b)
case sp
when ArvadosModel
visited[uuid] = job.as_api_response
if direction == :search_up
# Follow upstream collections referenced in the script parameters
- find_collections(visited, job) do |hash, uuid|
+ find_collections(visited, job) do |hash, col_uuid|
search_edges(visited, hash, :search_up) if hash
- search_edges(visited, uuid, :search_up) if uuid
+ search_edges(visited, col_uuid, :search_up) if col_uuid
end
elsif direction == :search_down
# Follow downstream job output
protected
def load_limit_offset_order_params *args
+ super
if action_name == 'index'
- # Omit manifest_text from index results unless expressly selected.
- @select ||= model_class.selectable_attributes - ["manifest_text"]
+ # Omit manifest_text and unsigned_manifest_text from index results unless expressly selected.
+ @select ||= model_class.selectable_attributes - ["manifest_text", "unsigned_manifest_text"]
end
- super
end
end
accept_attribute_as_json :runtime_constraints, Hash
accept_attribute_as_json :command, Array
accept_attribute_as_json :filters, Array
+ accept_attribute_as_json :scheduling_parameters, Hash
end
accept_attribute_as_json :mounts, Hash
accept_attribute_as_json :runtime_constraints, Hash
accept_attribute_as_json :command, Array
+ accept_attribute_as_json :scheduling_parameters, Hash
skip_before_filter :find_object_by_uuid, only: [:current]
skip_before_filter :render_404_if_no_object, only: [:current]
Collection,
Human, Specimen, Trait]
- table_names = klasses.map(&:table_name)
+ table_names = Hash[klasses.collect { |k| [k, k.table_name] }]
+
+ disabled_methods = Rails.configuration.disable_api_methods
+ avail_klasses = table_names.select{|k, t| !disabled_methods.include?(t+'.index')}
+ klasses = avail_klasses.keys
+
request_filters.each do |col, op, val|
- if col.index('.') && !table_names.include?(col.split('.', 2)[0])
+ if col.index('.') && !table_names.values.include?(col.split('.', 2)[0])
raise ArgumentError.new("Invalid attribute '#{col}' in filter")
end
end
if Rails.application.config.websocket_address
discovery[:websocketUrl] = Rails.application.config.websocket_address
elsif ENV['ARVADOS_WEBSOCKETS']
- discovery[:websocketUrl] = (root_url.sub /^http/, 'ws') + "websocket"
+ discovery[:websocketUrl] = root_url.sub(/^http/, 'ws') + "websocket"
end
ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
method = d_methods[action.to_sym]
end
if ctl_class.respond_to? "_#{action}_requires_parameters".to_sym
- ctl_class.send("_#{action}_requires_parameters".to_sym).each do |k, v|
+ ctl_class.send("_#{action}_requires_parameters".to_sym).each do |l, v|
if v.is_a? Hash
- method[:parameters][k] = v
+ method[:parameters][l] = v
else
- method[:parameters][k] = {}
+ method[:parameters][l] = {}
end
- if !method[:parameters][k][:default].nil?
+ if !method[:parameters][l][:default].nil?
# The JAVA SDK is sensitive to all values being strings
- method[:parameters][k][:default] = method[:parameters][k][:default].to_s
+ method[:parameters][l][:default] = method[:parameters][l][:default].to_s
end
- method[:parameters][k][:type] ||= 'string'
- method[:parameters][k][:description] ||= ''
- method[:parameters][k][:location] = (route.segment_keys.include?(k) ? 'path' : 'query')
- if method[:parameters][k][:required].nil?
- method[:parameters][k][:required] = v != false
+ method[:parameters][l][:type] ||= 'string'
+ method[:parameters][l][:description] ||= ''
+ method[:parameters][l][:location] = (route.segment_keys.include?(l) ? 'path' : 'query')
+ if method[:parameters][l][:required].nil?
+ method[:parameters][l][:required] = v != false
end
end
end
# use this installation.
@objects = []
else
- current_user_uuid = current_user.uuid
act_as_system_user do
uuids = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
system_user_uuid,
'require',
system_user_uuid,
Collection.uuid_like_pattern).
- collect &:head_uuid
+ collect(&:head_uuid)
@objects = Collection.where('uuid in (?)', uuids)
end
end
end
def apply_filters(model_class=nil)
- return super if @read_users.any? &:is_admin
+ return super if @read_users.any?(&:is_admin)
if params[:uuid] != current_user.andand.uuid
# Non-admin index/show returns very basic information about readable users.
safe_attrs = ["uuid", "is_active", "email", "first_name", "last_name"]
@users = {}
User.eager_load(:authorized_keys).
where('users.uuid in (?)',
- @vms.map { |vm| vm.login_permissions.map &:tail_uuid }.flatten.uniq).
+ @vms.map { |vm| vm.login_permissions.map(&:tail_uuid) }.flatten.uniq).
each do |u|
@users[u.uuid] = u
end
# we can tell they're not valuable.
user_uuids = User.
where('email is null or email not like ?', '%@example.com').
- collect &:uuid
+ collect(&:uuid)
fixture_uuids =
YAML::load_file(File.expand_path('../../../test/fixtures/users.yml',
__FILE__)).
# Create a new ArvadosApiToken handler
# +app+ The next layer of the Rack stack.
def initialize(app = nil, options = nil)
- @app = app if app.respond_to?(:call)
+ @app = app.respond_to?(:call) ? app : nil
end
def call env
if forked && EM.reactor_running?
EM.stop
end
- Thread.new {
- EM.run
- }
+ Thread.new do
+ begin
+ EM.run
+ ensure
+ ActiveRecord::Base.connection.close
+ end
+ end
die_gracefully_on_signal
end
else
# faciliates debugging
Thread.abort_on_exception = true
# just spawn a thread and start it up
- Thread.new {
- EM.run
- }
+ Thread.new do
+ begin
+ EM.run
+ ensure
+ ActiveRecord::Base.connection.close
+ end
+ end
end
# Create actual handler instance object from handler class.
end
def logged_attributes
- attributes.except *Rails.configuration.unlogged_attributes
+ attributes.except(*Rails.configuration.unlogged_attributes)
end
def self.full_text_searchable_columns
parts = full_text_searchable_columns.collect do |column|
"coalesce(#{column},'')"
end
- # We prepend a space to the tsvector() argument here. Otherwise,
- # it might start with a column that has its own (non-full-text)
- # index, which causes Postgres to use the column index instead of
- # the tsvector index, which causes full text queries to be just as
- # slow as if we had no index at all.
- "to_tsvector('english', ' ' || #{parts.join(" || ' ' || ")})"
+ "to_tsvector('english', #{parts.join(" || ' ' || ")})"
end
def self.apply_filters query, filters
end
def foreign_key_attributes
- attributes.keys.select { |a| a.match /_uuid$/ }
+ attributes.keys.select { |a| a.match(/_uuid$/) }
end
def skip_uuid_read_permission_check
foreign_key_attributes.each do |attr|
attr_value = send attr
if attr_value.is_a? String and
- attr_value.match /^[0-9a-f]{32,}(\+[@\w]+)*$/
+ attr_value.match(/^[0-9a-f]{32,}(\+[@\w]+)*$/)
begin
send "#{attr}=", Collection.normalize_uuid(attr_value)
rescue
unless uuid.is_a? String
return nil
end
- resource_class = nil
uuid.match HasUuid::UUID_REGEX do |re|
return uuid_prefixes[re[1]] if uuid_prefixes[re[1]]
end
- if uuid.match /.+@.+/
+ if uuid.match(/.+@.+/)
return Email
end
if self == ArvadosModel
# If called directly as ArvadosModel.find_by_uuid rather than via subclass,
# delegate to the appropriate subclass based on the given uuid.
- self.resource_class_for_uuid(uuid).find_by_uuid(uuid)
+ self.resource_class_for_uuid(uuid).unscoped.find_by_uuid(uuid)
else
super
end
# Return value: true if the locator has a valid signature, false otherwise
# Arguments: signed_blob_locator, opts
#
- def self.verify_signature *args
+ def self.verify_signature(*args)
begin
- self.verify_signature! *args
+ self.verify_signature!(*args)
true
rescue Blob::InvalidSignatureError
false
require 'arvados/keep'
+require 'sweep_trashed_collections'
class Collection < ArvadosModel
extend DbCurrentTime
serialize :properties, Hash
+ before_validation :set_validation_timestamp
before_validation :default_empty_manifest
before_validation :check_encoding
before_validation :check_manifest_validity
before_validation :check_signatures
before_validation :strip_signatures_and_update_replication_confirmed
+ before_validation :ensure_trash_at_not_in_past
+ before_validation :sync_trash_state
+ before_validation :default_trash_interval
validate :ensure_pdh_matches_manifest_text
+ validate :validate_trash_and_delete_timing
before_save :set_file_names
- before_save :expires_at_not_in_past
- # Query only undeleted collections by default.
- default_scope where("expires_at IS NULL or expires_at > statement_timestamp()")
+ # Query only untrashed collections by default.
+ default_scope where("is_trashed = false")
api_accessible :user, extend: :common do |t|
t.add :name
t.add :properties
t.add :portable_data_hash
t.add :signed_manifest_text, as: :manifest_text
+ t.add :manifest_text, as: :unsigned_manifest_text
t.add :replication_desired
t.add :replication_confirmed
t.add :replication_confirmed_at
- t.add :expires_at
+ t.add :delete_at
+ t.add :trash_at
+ t.add :is_trashed
+ end
+
+ after_initialize do
+ @signatures_checked = false
+ @computed_pdh_for_manifest_text = false
end
def self.attributes_required_columns
# API response, and never let clients select the
# manifest_text column.
#
- # We need expires_at to determine the correct
- # timestamp in signed_manifest_text.
- 'manifest_text' => ['manifest_text', 'expires_at'],
+ # We need trash_at and is_trashed to determine the
+ # correct timestamp in signed_manifest_text.
+ 'manifest_text' => ['manifest_text', 'trash_at', 'is_trashed'],
+ 'unsigned_manifest_text' => ['manifest_text'],
)
end
# subsequent passes without checking any signatures. This is
# important because the signatures have probably been stripped off
# by the time we get to a second validation pass!
- return true if @signatures_checked and @signatures_checked == computed_pdh
+ if @signatures_checked && @signatures_checked == computed_pdh
+ return true
+ end
if self.manifest_text_changed?
# Check permissions on the collection manifest.
api_token = current_api_client_authorization.andand.api_token
signing_opts = {
api_token: api_token,
- now: db_current_time.to_i,
+ now: @validation_timestamp.to_i,
}
self.manifest_text.each_line do |entry|
entry.split.each do |tok|
utf8 = manifest_text
utf8.force_encoding Encoding::UTF_8
if utf8.valid_encoding? and utf8 == manifest_text.encode(Encoding::UTF_8)
- manifest_text = utf8
+ self.manifest_text = utf8
return true
end
rescue
end
def signed_manifest_text
- if has_attribute? :manifest_text
+ if !has_attribute? :manifest_text
+ return nil
+ elsif is_trashed
+ return manifest_text
+ else
token = current_api_client_authorization.andand.api_token
exp = [db_current_time.to_i + Rails.configuration.blob_signature_ttl,
- expires_at].compact.map(&:to_i).min
- @signed_manifest_text = self.class.sign_manifest manifest_text, token, exp
+ trash_at].compact.map(&:to_i).min
+ self.class.sign_manifest manifest_text, token, exp
end
end
hash_part = nil
size_part = nil
uuid.split('+').each do |token|
- if token.match /^[0-9a-f]{32,}$/
+ if token.match(/^[0-9a-f]{32,}$/)
raise "uuid #{uuid} has multiple hash parts" if hash_part
hash_part = token
- elsif token.match /^\d+$/
+ elsif token.match(/^\d+$/)
raise "uuid #{uuid} has multiple size parts" if size_part
size_part = token
end
super - ["manifest_text"]
end
+ def self.where *args
+ SweepTrashedCollections.sweep_if_stale
+ super
+ end
+
protected
def portable_manifest_text
self.class.munge_manifest_locators(manifest_text) do |match|
super
end
- # If expires_at is being changed to a time in the past, change it to
+ # Use a single timestamp for all validations, even though each
+ # validation runs at a different time.
+ def set_validation_timestamp
+ @validation_timestamp = db_current_time
+ end
+
+ # If trash_at is being changed to a time in the past, change it to
# now. This allows clients to say "expires {client-current-time}"
# without failing due to clock skew, while avoiding odd log entries
# like "expiry date changed to {1 year ago}".
- def expires_at_not_in_past
- if expires_at_changed? and expires_at
- self.expires_at = [db_current_time, expires_at].max
+ def ensure_trash_at_not_in_past
+ if trash_at_changed? && trash_at
+ self.trash_at = [@validation_timestamp, trash_at].max
end
end
+
+ # Caller can move into/out of trash by setting/clearing is_trashed
+ # -- however, if the caller also changes trash_at, then any changes
+ # to is_trashed are ignored.
+ def sync_trash_state
+ if is_trashed_changed? && !trash_at_changed?
+ if is_trashed
+ self.trash_at = @validation_timestamp
+ else
+ self.trash_at = nil
+ self.delete_at = nil
+ end
+ end
+ self.is_trashed = trash_at && trash_at <= @validation_timestamp || false
+ true
+ end
+
+ # If trash_at is updated without touching delete_at, automatically
+ # update delete_at to a sensible value.
+ def default_trash_interval
+ if trash_at_changed? && !delete_at_changed?
+ if trash_at.nil?
+ self.delete_at = nil
+ else
+ self.delete_at = trash_at + Rails.configuration.default_trash_lifetime.seconds
+ end
+ end
+ end
+
+ def validate_trash_and_delete_timing
+ if trash_at.nil? != delete_at.nil?
+ errors.add :delete_at, "must be set if trash_at is set, and must be nil otherwise"
+ end
+
+ earliest_delete = ([@validation_timestamp, trash_at_was].compact.min +
+ Rails.configuration.blob_signature_ttl.seconds)
+ if delete_at && delete_at < earliest_delete
+ errors.add :delete_at, "#{delete_at} is too soon: earliest allowed is #{earliest_delete}"
+ end
+
+ if delete_at && delete_at < trash_at
+ errors.add :delete_at, "must not be earlier than trash_at"
+ end
+
+ true
+ end
end
@gitdirbase = Rails.configuration.git_repositories_dir
self.is = nil
Dir.foreach @gitdirbase do |repo|
- next if repo.match /^\./
+ next if repo.match(/^\./)
git_dir = repo.match(/\.git$/) ? repo : File.join(repo, '.git')
repo_name = repo.sub(/\.git$/, '')
ENV['GIT_DIR'] = File.join(@gitdirbase, git_dir)
- IO.foreach("|git rev-list --format=oneline '#{self.descendant.gsub /[^0-9a-f]/,""}'") do |line|
+ IO.foreach("|git rev-list --format=oneline '#{self.descendant.gsub(/[^0-9a-f]/,"")}'") do |line|
self.is = false
- sha1, message = line.strip.split(" ", 2)
+ sha1, _ = line.strip.split(" ", 2)
if sha1 == self.ancestor
self.is = true
break
serialize :mounts, Hash
serialize :runtime_constraints, Hash
serialize :command, Array
+ serialize :scheduling_parameters, Hash
before_validation :fill_field_defaults, :if => :new_record?
before_validation :set_timestamps
t.add :started_at
t.add :state
t.add :auth_uuid
+ t.add :scheduling_parameters
end
# Supported states for a container
self.mounts ||= {}
self.cwd ||= "."
self.priority ||= 1
+ self.scheduling_parameters ||= {}
end
def permission_to_create
if self.new_record?
permitted.push(:owner_uuid, :command, :container_image, :cwd,
:environment, :mounts, :output_path, :priority,
- :runtime_constraints)
+ :runtime_constraints, :scheduling_parameters)
end
case self.state
if self.runtime_constraints_changed?
self.runtime_constraints = self.class.deep_sort_hash(self.runtime_constraints)
end
+ if self.scheduling_parameters_changed?
+ self.scheduling_parameters = self.class.deep_sort_hash(self.scheduling_parameters)
+ end
end
def handle_completed
act_as_system_user do
if self.state == Cancelled
- retryable_requests = ContainerRequest.where("priority > 0 and state = 'Committed' and container_count < container_count_max")
+ retryable_requests = ContainerRequest.where("container_uuid = ? and priority > 0 and state = 'Committed' and container_count < container_count_max", uuid)
else
retryable_requests = []
end
output_path: self.output_path,
container_image: self.container_image,
mounts: self.mounts,
- runtime_constraints: self.runtime_constraints
+ runtime_constraints: self.runtime_constraints,
+ scheduling_parameters: self.scheduling_parameters
}
c = Container.create! c_attrs
retryable_requests.each do |cr|
serialize :mounts, Hash
serialize :runtime_constraints, Hash
serialize :command, Array
+ serialize :scheduling_parameters, Hash
before_validation :fill_field_defaults, :if => :new_record?
before_validation :validate_runtime_constraints
+ before_validation :validate_scheduling_parameters
before_validation :set_container
validates :command, :container_image, :output_path, :cwd, :presence => true
validate :validate_state_change
t.add :environment
t.add :expires_at
t.add :filters
+ t.add :log_uuid
t.add :mounts
t.add :name
+ t.add :output_name
t.add :output_path
+ t.add :output_uuid
t.add :priority
t.add :properties
t.add :requesting_container_uuid
t.add :runtime_constraints
+ t.add :scheduling_parameters
t.add :state
t.add :use_existing
end
# Finalize the container request after the container has
# finished/cancelled.
def finalize!
- update_attributes!(state: Final)
+ out_coll = nil
+ log_coll = nil
c = Container.find_by_uuid(container_uuid)
['output', 'log'].each do |out_type|
pdh = c.send(out_type)
next if pdh.nil?
+ if self.output_name and out_type == 'output'
+ coll_name = self.output_name
+ else
+ coll_name = "Container #{out_type} for request #{uuid}"
+ end
manifest = Collection.where(portable_data_hash: pdh).first.manifest_text
- Collection.create!(owner_uuid: owner_uuid,
- manifest_text: manifest,
- portable_data_hash: pdh,
- name: "Container #{out_type} for request #{uuid}",
- properties: {
- 'type' => out_type,
- 'container_request' => uuid,
- })
+ begin
+ coll = Collection.create!(owner_uuid: owner_uuid,
+ manifest_text: manifest,
+ portable_data_hash: pdh,
+ name: coll_name,
+ properties: {
+ 'type' => out_type,
+ 'container_request' => uuid,
+ })
+ rescue ActiveRecord::RecordNotUnique => rn
+ # In case this is executed as part of a transaction: When a Postgres exception happens,
+ # the following statements on the same transaction become invalid, so a rollback is
+ # needed. One example are Unit Tests, every test is enclosed inside a transaction so
+ # that the database can be reverted before every new test starts.
+ # See: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Exception+handling+and+rolling+back
+ ActiveRecord::Base.connection.execute 'ROLLBACK'
+ raise unless out_type == 'output' and self.output_name
+ # Postgres specific unique name check. See ApplicationController#create for
+ # a detailed explanation.
+ raise unless rn.original_exception.is_a? PG::UniqueViolation
+ err = rn.original_exception
+ detail = err.result.error_field(PG::Result::PG_DIAG_MESSAGE_DETAIL)
+ raise unless /^Key \(owner_uuid, name\)=\([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}, .*?\) already exists\./.match detail
+ # Output collection name collision detected: append a timestamp.
+ coll_name = "#{self.output_name} #{Time.now.getgm.strftime('%FT%TZ')}"
+ retry
+ end
+ if out_type == 'output'
+ out_coll = coll.uuid
+ else
+ log_coll = coll.uuid
+ end
end
+ update_attributes!(state: Final, output_uuid: out_coll, log_uuid: log_coll)
end
protected
self.mounts ||= {}
self.cwd ||= "."
self.container_count_max ||= Rails.configuration.container_count_max
+ self.scheduling_parameters ||= {}
end
# Create a new container (or find an existing one) to satisfy this
if not reusable.nil?
reusable
else
+ c_attrs[:scheduling_parameters] = self.scheduling_parameters
Container.create!(c_attrs)
end
end
end
end
+ def validate_scheduling_parameters
+ if self.state == Committed
+ if scheduling_parameters.include? 'partitions' and
+ (!scheduling_parameters['partitions'].is_a?(Array) ||
+ scheduling_parameters['partitions'].reject{|x| !x.is_a?(String)}.size !=
+ scheduling_parameters['partitions'].size)
+ errors.add :scheduling_parameters, "partitions must be an array of strings"
+ end
+ end
+ end
+
def validate_change
permitted = [:owner_uuid]
:container_image, :cwd, :description, :environment,
:filters, :mounts, :name, :output_path, :priority,
:properties, :requesting_container_uuid, :runtime_constraints,
- :state, :container_uuid, :use_existing
+ :state, :container_uuid, :use_existing, :scheduling_parameters,
+ :output_name
when Committed
if container_uuid.nil?
end
# Can update priority, container count, name and description
- permitted.push :priority, :container_count, :container_count_max, :container_uuid, :name, :description
+ permitted.push :priority, :container_count, :container_count_max, :container_uuid,
+ :name, :description
if self.state_changed?
# Allow create-and-commit in a single operation.
permitted.push :command, :container_image, :cwd, :description, :environment,
:filters, :mounts, :name, :output_path, :properties,
:requesting_container_uuid, :runtime_constraints,
- :state, :container_uuid
+ :state, :container_uuid, :use_existing, :scheduling_parameters,
+ :output_name
end
when Final
errors.add :state, "of container request can only be set to Final by system."
end
- if self.state_changed? || self.name_changed? || self.description_changed?
- permitted.push :state, :name, :description
+ if self.state_changed? || self.name_changed? || self.description_changed? || self.output_uuid_changed? || self.log_uuid_changed?
+ permitted.push :state, :name, :description, :output_uuid, :log_uuid
else
errors.add :state, "does not allow updates"
end
(Complete = 'Complete'),
]
+ after_initialize do
+ @need_crunch_dispatch_trigger = false
+ end
+
def assert_finished
update_attributes(finished_at: finished_at || db_current_time,
success: success.nil? ? false : success,
super - ["script_parameters_digest"]
end
+ def self.full_text_searchable_columns
+ super - ["script_parameters_digest"]
+ end
+
def self.load_job_specific_filters attrs, orig_filters, read_users
# Convert Job-specific @filters entries into general SQL filters.
script_info = {"repository" => nil, "script" => nil}
assign_uuid
Commit.tag_in_internal_repository repository, script_version, uuid
rescue
- uuid = uuid_was
+ self.uuid = uuid_was
raise
end
end
output_changed? or
log_changed? or
tasks_summary_changed? or
- state_changed? or
+ (state_changed? && state != Cancelled) or
components_changed?
logger.warn "User #{current_user.uuid if current_user} tried to change protected job attributes on locked #{self.class.to_s} #{uuid_was}"
return false
end
def ensure_no_collection_uuids_in_script_params
- # recursive_hash_search searches recursively through hashes and
- # arrays in 'thing' for string fields matching regular expression
- # 'pattern'. Returns true if pattern is found, false otherwise.
- def recursive_hash_search thing, pattern
- if thing.is_a? Hash
- thing.each do |k, v|
- return true if recursive_hash_search v, pattern
- end
- elsif thing.is_a? Array
- thing.each do |k|
- return true if recursive_hash_search k, pattern
- end
- elsif thing.is_a? String
- return true if thing.match pattern
- end
- false
- end
-
# Fail validation if any script_parameters field includes a string containing a
# collection uuid pattern.
if self.script_parameters_changed?
end
true
end
+
+ # recursive_hash_search searches recursively through hashes and
+ # arrays in 'thing' for string fields matching regular expression
+ # 'pattern'. Returns true if pattern is found, false otherwise.
+ def recursive_hash_search thing, pattern
+ if thing.is_a? Hash
+ thing.each do |k, v|
+ return true if recursive_hash_search v, pattern
+ end
+ elsif thing.is_a? Array
+ thing.each do |k|
+ return true if recursive_hash_search k, pattern
+ end
+ elsif thing.is_a? String
+ return true if thing.match pattern
+ end
+ false
+ end
end
after_update :maybe_invalidate_permissions_cache
after_create :maybe_invalidate_permissions_cache
after_destroy :maybe_invalidate_permissions_cache
- attr_accessor :head_kind, :tail_kind
validate :name_links_are_obsolete
api_accessible :user, extend: :common do |t|
include CommonApiTemplate
serialize :properties, Hash
before_validation :set_default_event_at
- attr_accessor :object, :object_kind
after_save :send_notify
api_accessible :user, extend: :common do |t|
t.add lambda { |x| Rails.configuration.compute_node_nameservers }, :as => :nameservers
end
+ after_initialize do
+ @bypass_arvados_authorization = false
+ end
+
def domain
super || Rails.configuration.compute_node_domain
end
(0..Rails.configuration.max_compute_nodes-1).each do |slot_number|
hostname = hostname_for_slot(slot_number)
hostfile = File.join Rails.configuration.dns_server_conf_dir, "#{hostname}.conf"
- if !File.exists? hostfile
+ if !File.exist? hostfile
n = Node.where(:slot_number => slot_number).first
if n.nil? or n.ip_address.nil?
dns_server_update(hostname, UNUSED_NODE_IP)
before_validation :bootstrap_components
before_validation :update_state
before_validation :verify_status
+ before_validation :update_timestamps_when_state_changes
before_create :set_state_before_save
before_save :set_state_before_save
end
end
+ def update_timestamps_when_state_changes
+ return if not (state_changed? or new_record?)
+
+ case state
+ when RunningOnServer, RunningOnClient
+ self.started_at ||= db_current_time
+ when Failed, Complete
+ current_time = db_current_time
+ self.started_at ||= current_time
+ self.finished_at ||= current_time
+ end
+ end
+
end
prefix_match = Regexp.escape(owner.username + "/")
errmsg_start = "must be the owner's username, then '/', then"
end
- if not /^#{prefix_match}[A-Za-z][A-Za-z0-9]*$/.match(name)
+ if not (/^#{prefix_match}[A-Za-z][A-Za-z0-9]*$/.match(name))
errors.add(:name,
"#{errmsg_start} a letter followed by alphanumerics")
false
ALL_PERMISSIONS = {read: true, write: true, manage: true}
+ # Map numeric permission levels (see lib/create_permission_view.sql)
+ # back to read/write/manage flags.
+ PERMS_FOR_VAL =
+ [{},
+ {read: true},
+ {read: true, write: true},
+ {read: true, write: true, manage: true}]
+
def full_name
"#{first_name} #{last_name}".strip
end
def is_invited
!!(self.is_active ||
Rails.configuration.new_users_are_active ||
- self.groups_i_can(:read).select { |x| x.match /-f+$/ }.first)
+ self.groups_i_can(:read).select { |x| x.match(/-f+$/) }.first)
end
def groups_i_can(verb)
# Return a hash of {group_uuid: perm_hash} where perm_hash[:read]
# and perm_hash[:write] are true if this user can read and write
# objects owned by group_uuid.
- #
- # The permission graph is built by repeatedly enumerating all
- # permission links reachable from self.uuid, and then calling
- # search_permissions
def calculate_group_permissions
- permissions_from = {}
- todo = {self.uuid => true}
- done = {}
- # Build the equivalence class of permissions starting with
- # self.uuid. On each iteration of this loop, todo contains
- # the next set of uuids in the permission equivalence class
- # to evaluate.
- while !todo.empty?
- lookup_uuids = todo.keys
- lookup_uuids.each do |uuid| done[uuid] = true end
- todo = {}
- newgroups = []
- # include all groups owned by the current set of uuids.
- Group.where('owner_uuid in (?)', lookup_uuids).each do |group|
- newgroups << [group.owner_uuid, group.uuid, 'can_manage']
- end
- # add any permission links from the current lookup_uuids to a Group.
- Link.where('link_class = ? and tail_uuid in (?) and ' \
- '(head_uuid like ? or (name = ? and head_uuid like ?))',
- 'permission',
- lookup_uuids,
- Group.uuid_like_pattern,
- 'can_manage',
- User.uuid_like_pattern).each do |link|
- newgroups << [link.tail_uuid, link.head_uuid, link.name]
- end
- newgroups.each do |tail_uuid, head_uuid, perm_name|
- unless done.has_key? head_uuid
- todo[head_uuid] = true
- end
- link_permissions = {}
- case perm_name
- when 'can_read'
- link_permissions = {read:true}
- when 'can_write'
- link_permissions = {read:true,write:true}
- when 'can_manage'
- link_permissions = ALL_PERMISSIONS
- end
- permissions_from[tail_uuid] ||= {}
- permissions_from[tail_uuid][head_uuid] ||= {}
- link_permissions.each do |k,v|
- permissions_from[tail_uuid][head_uuid][k] ||= v
- end
- end
+ conn = ActiveRecord::Base.connection
+ self.class.transaction do
+ # Check whether the temporary view has already been created
+ # during this connection. If not, create it.
+ conn.exec_query 'SAVEPOINT check_permission_view'
+ begin
+ conn.exec_query('SELECT 1 FROM permission_view LIMIT 0')
+ rescue
+ conn.exec_query 'ROLLBACK TO SAVEPOINT check_permission_view'
+ sql = File.read(Rails.root.join('lib', 'create_permission_view.sql'))
+ conn.exec_query(sql)
+ ensure
+ conn.exec_query 'RELEASE SAVEPOINT check_permission_view'
end
- perms = search_permissions(self.uuid, permissions_from)
- Rails.cache.write "groups_for_user_#{self.uuid}", perms
- perms
+ end
+
+ group_perms = {}
+ conn.exec_query('SELECT target_owner_uuid, max(perm_level)
+ FROM permission_view
+ WHERE user_uuid = $1
+ AND target_owner_uuid IS NOT NULL
+ GROUP BY target_owner_uuid',
+ # "name" arg is a query label that appears in logs:
+ "group_permissions for #{uuid}",
+ # "binds" arg is an array of [col_id, value] for '$1' vars:
+ [[nil, uuid]],
+ ).rows.each do |group_uuid, max_p_val|
+ group_perms[group_uuid] = PERMS_FOR_VAL[max_p_val.to_i]
+ end
+ Rails.cache.write "groups_for_user_#{self.uuid}", group_perms
+ group_perms
end
# Return a hash of {group_uuid: perm_hash} where perm_hash[:read]
# delete "All users" group read permissions for this user
group = Group.where(name: 'All users').select do |g|
- g[:uuid].match /-f+$/
+ g[:uuid].match(/-f+$/)
end.first
Link.destroy_all(tail_uuid: self.uuid,
head_uuid: group[:uuid],
# The default is 2 weeks.
blob_signature_ttl: 1209600
- # Default lifetime for ephemeral collections: 2 weeks.
+ # Default lifetime for ephemeral collections: 2 weeks. This must not
+ # be less than blob_signature_ttl.
default_trash_lifetime: 1209600
+ # Interval (seconds) between trash sweeps. During a trash sweep,
+ # collections are marked as trash if their trash_at time has
+ # arrived, and deleted if their delete_at time has arrived.
+ trash_sweep_interval: 60
+
# Maximum characters of (JSON-encoded) query parameters to include
# in each request log entry. When params exceed this size, they will
# be JSON-encoded, truncated to this size, and logged as
workbench_address: https://localhost:3001/
git_repositories_dir: <%= Rails.root.join 'tmp', 'git', 'test' %>
git_internal_dir: <%= Rails.root.join 'tmp', 'internal.git' %>
+ websocket_address: <% if ENV['ARVADOS_TEST_EXPERIMENTAL_WS'] %>"wss://0.0.0.0:<%= ENV['ARVADOS_TEST_WSS_PORT'] %>/websocket"<% else %>false<% end %>
+ trash_sweep_interval: -1
config.filter_parameters += [:password]
I18n.enforce_available_locales = false
+
+ # Before using the filesystem backend for Rails.cache, check
+ # whether we own the relevant directory. If we don't, using it is
+ # likely to either fail or (if we're root) pollute it and cause
+ # other processes to fail later.
+ default_cache_path = Rails.root.join('tmp', 'cache')
+ if not File.owned?(default_cache_path)
+ if File.exist?(default_cache_path)
+ why = "owner (uid=#{File::Stat.new(default_cache_path).uid}) " +
+ "is not me (uid=#{Process.euid})"
+ else
+ why = "does not exist"
+ end
+ STDERR.puts("Defaulting to memory cache, " +
+ "because #{default_cache_path} #{why}")
+ config.cache_store = :memory_store
+ end
end
end
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
-require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
+require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
# end
ActiveSupport::Inflector.inflections do |inflect|
- inflect.plural /^([Ss]pecimen)$/i, '\1s'
- inflect.singular /^([Ss]pecimen)s?/i, '\1'
- inflect.plural /^([Hh]uman)$/i, '\1s'
- inflect.singular /^([Hh]uman)s?/i, '\1'
+ inflect.plural(/^([Ss]pecimen)$/i, '\1s')
+ inflect.singular(/^([Ss]pecimen)s?/i, '\1')
+ inflect.plural(/^([Hh]uman)$/i, '\1s')
+ inflect.singular(/^([Hh]uman)s?/i, '\1')
end
# configured by application.yml (i.e., here!) instead.
end
-if (File.exists?(File.expand_path '../omniauth.rb', __FILE__) and
+if (File.exist?(File.expand_path '../omniauth.rb', __FILE__) and
not defined? WARNED_OMNIAUTH_CONFIG)
Rails.logger.warn <<-EOS
DEPRECATED CONFIGURATION:
%w(application.default application).each do |cfgfile|
path = "#{::Rails.root.to_s}/config/#{cfgfile}.yml"
- if File.exists? path
+ if File.exist? path
yaml = ERB.new(IO.read path).result(binding)
confs = YAML.load(yaml, deserialize_symbols: true)
# Ignore empty YAML file:
if Rails.env == 'development'
Dir.foreach("#{Rails.root}/app/models") do |model_file|
- require_dependency model_file if model_file.match /\.rb$/
+ require_dependency model_file if model_file.match(/\.rb$/)
end
end
resources :collections do
get 'provenance', on: :member
get 'used_by', on: :member
+ post 'trash', on: :member
end
resources :groups do
get 'contents', on: :collection
--- /dev/null
+class AddSchedulingParametersToContainer < ActiveRecord::Migration
+ def change
+ add_column :containers, :scheduling_parameters, :text
+ add_column :container_requests, :scheduling_parameters, :text
+ end
+end
--- /dev/null
+require 'has_uuid'
+
+class AddOutputAndLogUuidToContainerRequest < ActiveRecord::Migration
+ extend HasUuid::ClassMethods
+
+ def up
+ add_column :container_requests, :output_uuid, :string
+ add_column :container_requests, :log_uuid, :string
+
+ no_such_out_coll = Server::Application.config.uuid_prefix + '-' + '4zz18' + '-xxxxxxxxxxxxxxx'
+ no_such_log_coll = Server::Application.config.uuid_prefix + '-' + '4zz18' + '-yyyyyyyyyyyyyyy'
+
+ update_sql <<-EOS
+update container_requests set output_uuid = ('#{no_such_out_coll}'), log_uuid = ('#{no_such_log_coll}');
+EOS
+ end
+
+ def down
+ remove_column :container_requests, :log_uuid
+ remove_column :container_requests, :output_uuid
+ end
+end
--- /dev/null
+class AddOutputAndLogUuidsToContainerRequestSearchIndex < ActiveRecord::Migration
+ def up
+ begin
+ remove_index :container_requests, :name => 'container_requests_search_index'
+ rescue
+ end
+ add_index :container_requests,
+ ["uuid", "owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "name", "state", "requesting_container_uuid", "container_uuid", "container_image", "cwd", "output_path", "output_uuid", "log_uuid"],
+ name: "container_requests_search_index"
+ end
+
+ def down
+ begin
+ remove_index :container_requests, :name => 'container_requests_search_index'
+ rescue
+ end
+ add_index :container_requests,
+ ["uuid", "owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "name", "state", "requesting_container_uuid", "container_uuid", "container_image", "cwd", "output_path"],
+ name: "container_requests_search_index"
+ end
+end
--- /dev/null
+class FullTextSearchIndexes < ActiveRecord::Migration
+ def fts_indexes
+ {
+ "collections" => "collections_full_text_search_idx",
+ "container_requests" => "container_requests_full_text_search_idx",
+ "groups" => "groups_full_text_search_idx",
+ "jobs" => "jobs_full_text_search_idx",
+ "pipeline_instances" => "pipeline_instances_full_text_search_idx",
+ "pipeline_templates" => "pipeline_templates_full_text_search_idx",
+ "workflows" => "workflows_full_text_search_idx",
+ }
+ end
+
+ def up
+ # remove existing fts indexes and create up to date ones with no leading space
+ fts_indexes.each do |t, i|
+ t.classify.constantize.reset_column_information
+ ActiveRecord::Base.connection.indexes(t).each do |idx|
+ if idx.name == i
+ remove_index t.to_sym, :name => i
+ break
+ end
+ end
+ execute "CREATE INDEX #{i} ON #{t} USING gin(#{t.classify.constantize.full_text_tsvector});"
+ end
+ end
+
+ def down
+ fts_indexes.each do |t, i|
+ remove_index t.to_sym, :name => i
+ end
+ end
+end
--- /dev/null
+class SplitExpiryToTrashAndDelete < ActiveRecord::Migration
+ def up
+ Collection.transaction do
+ add_column(:collections, :trash_at, :datetime)
+ add_index(:collections, :trash_at)
+ add_column(:collections, :is_trashed, :boolean, null: false, default: false)
+ add_index(:collections, :is_trashed)
+ rename_column(:collections, :expires_at, :delete_at)
+ add_index(:collections, :delete_at)
+
+ Collection.reset_column_information
+ Collection.
+ where('delete_at is not null and delete_at <= statement_timestamp()').
+ delete_all
+ Collection.
+ where('delete_at is not null').
+ update_all('is_trashed = true, trash_at = statement_timestamp()')
+ add_index(:collections, [:owner_uuid, :name],
+ unique: true,
+ where: 'is_trashed = false',
+ name: 'index_collections_on_owner_uuid_and_name')
+ remove_index(:collections,
+ name: 'collection_owner_uuid_name_unique')
+ end
+ end
+
+ def down
+ Collection.transaction do
+ remove_index(:collections, :delete_at)
+ rename_column(:collections, :delete_at, :expires_at)
+ add_index(:collections, [:owner_uuid, :name],
+ unique: true,
+ where: 'expires_at is null',
+ name: 'collection_owner_uuid_name_unique')
+ remove_index(:collections,
+ name: 'index_collections_on_owner_uuid_and_name')
+ remove_column(:collections, :is_trashed)
+ remove_index(:collections, :trash_at)
+ remove_column(:collections, :trash_at)
+ end
+ end
+end
--- /dev/null
+class AddOutputNameToContainerRequests < ActiveRecord::Migration
+ def up
+ add_column :container_requests, :output_name, :string, :default => nil
+ end
+
+ def down
+ remove_column :container_requests, :output_name
+ end
+end
--- /dev/null
+class AddOutputNameToContainerRequestSearchIndex < ActiveRecord::Migration
+ def up
+ begin
+ remove_index :container_requests, :name => 'container_requests_search_index'
+ rescue
+ end
+ add_index :container_requests,
+ ["uuid", "owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "name", "state", "requesting_container_uuid", "container_uuid", "container_image", "cwd", "output_path", "output_uuid", "log_uuid", "output_name"],
+ name: "container_requests_search_index"
+ end
+
+ def down
+ begin
+ remove_index :container_requests, :name => 'container_requests_search_index'
+ rescue
+ end
+ add_index :container_requests,
+ ["uuid", "owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "name", "state", "requesting_container_uuid", "container_uuid", "container_image", "cwd", "output_path", "output_uuid", "log_uuid"],
+ name: "container_requests_search_index"
+ end
+end
--- /dev/null
+class AddOutputNameToCrFtsIndex < ActiveRecord::Migration
+ def up
+ t = "container_requests"
+ i = "container_requests_full_text_search_idx"
+ t.classify.constantize.reset_column_information
+ ActiveRecord::Base.connection.indexes(t).each do |idx|
+ if idx.name == i
+ remove_index t.to_sym, :name => i
+ break
+ end
+ end
+ # By now, container_request should have the new column "output_name" so full_text_tsvector
+ # would include it on its results
+ execute "CREATE INDEX #{i} ON #{t} USING gin(#{t.classify.constantize.full_text_tsvector});"
+ end
+
+ def down
+ t = "container_requests"
+ i = "container_requests_full_text_search_idx"
+ remove_index t.to_sym, :name => i
+ end
+end
--- /dev/null
+class SetFinishedAtOnFinishedPipelineInstances < ActiveRecord::Migration
+ def change
+ ActiveRecord::Base.connection.execute("update pipeline_instances set finished_at=updated_at where finished_at is null and (state='Failed' or state='Complete')")
+ end
+end
name character varying(255),
description character varying(524288),
properties text,
- expires_at timestamp without time zone,
- file_names character varying(8192)
+ delete_at timestamp without time zone,
+ file_names character varying(8192),
+ trash_at timestamp without time zone,
+ is_trashed boolean DEFAULT false NOT NULL
);
filters text,
updated_at timestamp without time zone NOT NULL,
container_count integer DEFAULT 0,
- use_existing boolean DEFAULT true
+ use_existing boolean DEFAULT true,
+ scheduling_parameters text,
+ output_uuid character varying(255),
+ log_uuid character varying(255),
+ output_name character varying(255) DEFAULT NULL::character varying
);
updated_at timestamp without time zone NOT NULL,
exit_code integer,
auth_uuid character varying(255),
- locked_by_uuid character varying(255)
+ locked_by_uuid character varying(255),
+ scheduling_parameters text
);
CREATE INDEX authorized_keys_search_index ON authorized_keys USING btree (uuid, owner_uuid, modified_by_client_uuid, modified_by_user_uuid, name, key_type, authorized_user_uuid);
---
--- Name: collection_owner_uuid_name_unique; Type: INDEX; Schema: public; Owner: -; Tablespace:
---
-
-CREATE UNIQUE INDEX collection_owner_uuid_name_unique ON collections USING btree (owner_uuid, name) WHERE (expires_at IS NULL);
-
-
--
-- Name: collections_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX collections_full_text_search_idx ON collections USING gin (to_tsvector('english'::regconfig, (((((((((((((((((' '::text || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(portable_data_hash, ''::character varying))::text) || ' '::text) || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(file_names, ''::character varying))::text)));
+CREATE INDEX collections_full_text_search_idx ON collections USING gin (to_tsvector('english'::regconfig, (((((((((((((((((COALESCE(owner_uuid, ''::character varying))::text || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(portable_data_hash, ''::character varying))::text) || ' '::text) || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(file_names, ''::character varying))::text)));
--
-- Name: container_requests_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX container_requests_full_text_search_idx ON container_requests USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((((((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(description, ''::text)) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || (COALESCE(requesting_container_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(container_uuid, ''::character varying))::text) || ' '::text) || COALESCE(mounts, ''::text)) || ' '::text) || COALESCE(runtime_constraints, ''::text)) || ' '::text) || (COALESCE(container_image, ''::character varying))::text) || ' '::text) || COALESCE(environment, ''::text)) || ' '::text) || (COALESCE(cwd, ''::character varying))::text) || ' '::text) || COALESCE(command, ''::text)) || ' '::text) || (COALESCE(output_path, ''::character varying))::text) || ' '::text) || COALESCE(filters, ''::text))));
+CREATE INDEX container_requests_full_text_search_idx ON container_requests USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((((((((((((((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(description, ''::text)) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || (COALESCE(requesting_container_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(container_uuid, ''::character varying))::text) || ' '::text) || COALESCE(mounts, ''::text)) || ' '::text) || COALESCE(runtime_constraints, ''::text)) || ' '::text) || (COALESCE(container_image, ''::character varying))::text) || ' '::text) || COALESCE(environment, ''::text)) || ' '::text) || (COALESCE(cwd, ''::character varying))::text) || ' '::text) || COALESCE(command, ''::text)) || ' '::text) || (COALESCE(output_path, ''::character varying))::text) || ' '::text) || COALESCE(filters, ''::text)) || ' '::text) || COALESCE(scheduling_parameters, ''::text)) || ' '::text) || (COALESCE(output_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(log_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(output_name, ''::character varying))::text)));
--
-- Name: container_requests_search_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX container_requests_search_index ON container_requests USING btree (uuid, owner_uuid, modified_by_client_uuid, modified_by_user_uuid, name, state, requesting_container_uuid, container_uuid, container_image, cwd, output_path);
+CREATE INDEX container_requests_search_index ON container_requests USING btree (uuid, owner_uuid, modified_by_client_uuid, modified_by_user_uuid, name, state, requesting_container_uuid, container_uuid, container_image, cwd, output_path, output_uuid, log_uuid, output_name);
--
-- Name: groups_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX groups_full_text_search_idx ON groups USING gin (to_tsvector('english'::regconfig, (((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || (COALESCE(group_class, ''::character varying))::text)));
+CREATE INDEX groups_full_text_search_idx ON groups USING gin (to_tsvector('english'::regconfig, (((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || (COALESCE(group_class, ''::character varying))::text)));
--
CREATE INDEX index_collections_on_created_at ON collections USING btree (created_at);
+--
+-- Name: index_collections_on_delete_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_collections_on_delete_at ON collections USING btree (delete_at);
+
+
+--
+-- Name: index_collections_on_is_trashed; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_collections_on_is_trashed ON collections USING btree (is_trashed);
+
+
--
-- Name: index_collections_on_modified_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_collections_on_owner_uuid ON collections USING btree (owner_uuid);
+--
+-- Name: index_collections_on_owner_uuid_and_name; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE UNIQUE INDEX index_collections_on_owner_uuid_and_name ON collections USING btree (owner_uuid, name) WHERE (is_trashed = false);
+
+
+--
+-- Name: index_collections_on_trash_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_collections_on_trash_at ON collections USING btree (trash_at);
+
+
--
-- Name: index_collections_on_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-- Name: jobs_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX jobs_full_text_search_idx ON jobs USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((((((((((((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(submit_id, ''::character varying))::text) || ' '::text) || (COALESCE(script, ''::character varying))::text) || ' '::text) || (COALESCE(script_version, ''::character varying))::text) || ' '::text) || COALESCE(script_parameters, ''::text)) || ' '::text) || (COALESCE(cancelled_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(cancelled_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(output, ''::character varying))::text) || ' '::text) || (COALESCE(is_locked_by_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(log, ''::character varying))::text) || ' '::text) || COALESCE(tasks_summary, ''::text)) || ' '::text) || COALESCE(runtime_constraints, ''::text)) || ' '::text) || (COALESCE(repository, ''::character varying))::text) || ' '::text) || (COALESCE(supplied_script_version, ''::character varying))::text) || ' '::text) || (COALESCE(docker_image_locator, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || (COALESCE(arvados_sdk_version, ''::character varying))::text)));
+CREATE INDEX jobs_full_text_search_idx ON jobs USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((((((((((((((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(submit_id, ''::character varying))::text) || ' '::text) || (COALESCE(script, ''::character varying))::text) || ' '::text) || (COALESCE(script_version, ''::character varying))::text) || ' '::text) || COALESCE(script_parameters, ''::text)) || ' '::text) || (COALESCE(cancelled_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(cancelled_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(output, ''::character varying))::text) || ' '::text) || (COALESCE(is_locked_by_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(log, ''::character varying))::text) || ' '::text) || COALESCE(tasks_summary, ''::text)) || ' '::text) || COALESCE(runtime_constraints, ''::text)) || ' '::text) || (COALESCE(repository, ''::character varying))::text) || ' '::text) || (COALESCE(supplied_script_version, ''::character varying))::text) || ' '::text) || (COALESCE(docker_image_locator, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || (COALESCE(arvados_sdk_version, ''::character varying))::text) || ' '::text) || COALESCE(components, ''::text))));
--
-- Name: pipeline_instances_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX pipeline_instances_full_text_search_idx ON pipeline_instances USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(pipeline_template_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(components, ''::text)) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || COALESCE(components_summary, ''::text)) || ' '::text) || (COALESCE(description, ''::character varying))::text)));
+CREATE INDEX pipeline_instances_full_text_search_idx ON pipeline_instances USING gin (to_tsvector('english'::regconfig, (((((((((((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(pipeline_template_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(components, ''::text)) || ' '::text) || COALESCE(properties, ''::text)) || ' '::text) || (COALESCE(state, ''::character varying))::text) || ' '::text) || COALESCE(components_summary, ''::text)) || ' '::text) || (COALESCE(description, ''::character varying))::text)));
--
-- Name: pipeline_templates_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX pipeline_templates_full_text_search_idx ON pipeline_templates USING gin (to_tsvector('english'::regconfig, (((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(components, ''::text)) || ' '::text) || (COALESCE(description, ''::character varying))::text)));
+CREATE INDEX pipeline_templates_full_text_search_idx ON pipeline_templates USING gin (to_tsvector('english'::regconfig, (((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(components, ''::text)) || ' '::text) || (COALESCE(description, ''::character varying))::text)));
--
-- Name: workflows_full_text_search_idx; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
-CREATE INDEX workflows_full_text_search_idx ON workflows USING gin (to_tsvector('english'::regconfig, (((((((((((((' '::text || (COALESCE(uuid, ''::character varying))::text) || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(description, ''::text)) || ' '::text) || COALESCE(definition, ''::text))));
+CREATE INDEX workflows_full_text_search_idx ON workflows USING gin (to_tsvector('english'::regconfig, (((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || COALESCE(description, ''::text)) || ' '::text) || COALESCE(definition, ''::text))));
--
INSERT INTO schema_migrations (version) VALUES ('20160926194129');
-INSERT INTO schema_migrations (version) VALUES ('20161019171346');
\ No newline at end of file
+INSERT INTO schema_migrations (version) VALUES ('20161019171346');
+
+INSERT INTO schema_migrations (version) VALUES ('20161111143147');
+
+INSERT INTO schema_migrations (version) VALUES ('20161115171221');
+
+INSERT INTO schema_migrations (version) VALUES ('20161115174218');
+
+INSERT INTO schema_migrations (version) VALUES ('20161213172944');
+
+INSERT INTO schema_migrations (version) VALUES ('20161222153434');
+
+INSERT INTO schema_migrations (version) VALUES ('20161223090712');
+
+INSERT INTO schema_migrations (version) VALUES ('20170102153111');
+
+INSERT INTO schema_migrations (version) VALUES ('20170105160301');
+
+INSERT INTO schema_migrations (version) VALUES ('20170105160302');
\ No newline at end of file
--- /dev/null
+CREATE TEMPORARY VIEW permission_view AS
+WITH RECURSIVE
+perm_value (name, val) AS (
+ VALUES
+ ('can_read', 1::smallint),
+ ('can_login', 1),
+ ('can_write', 2),
+ ('can_manage', 3)
+ ),
+perm_edges (tail_uuid, head_uuid, val, follow) AS (
+ SELECT links.tail_uuid,
+ links.head_uuid,
+ pv.val,
+ (pv.val = 3 OR groups.uuid IS NOT NULL) AS follow
+ FROM links
+ LEFT JOIN perm_value pv ON pv.name = links.name
+ LEFT JOIN groups ON pv.val<3 AND groups.uuid = links.head_uuid
+ WHERE links.link_class = 'permission'
+ UNION ALL
+ SELECT owner_uuid, uuid, 3, true FROM groups
+ ),
+perm (val, follow, user_uuid, target_uuid) AS (
+ SELECT 3::smallint AS val,
+ true AS follow,
+ users.uuid::varchar(32) AS user_uuid,
+ users.uuid::varchar(32) AS target_uuid
+ FROM users
+ UNION
+ SELECT LEAST(perm.val, edges.val)::smallint AS val,
+ edges.follow AS follow,
+ perm.user_uuid::varchar(32) AS user_uuid,
+ edges.head_uuid::varchar(32) AS target_uuid
+ FROM perm
+ INNER JOIN perm_edges edges
+ ON perm.follow AND edges.tail_uuid = perm.target_uuid
+)
+SELECT user_uuid,
+ target_uuid,
+ val AS perm_level,
+ CASE follow WHEN true THEN target_uuid ELSE NULL END AS target_owner_uuid
+ FROM perm;
api_client_auth = ApiClientAuthorization.
where(api_token: supplied_token).
first
- if api_client_auth && !api_client_auth.user.uuid.match(/-000000000000000$/)
- raise "Token already exists but is not a superuser token."
+ if !api_client_auth
+ # fall through to create a token
+ elsif !api_client_auth.user.uuid.match(/-000000000000000$/)
+ raise "Token exists but is not a superuser token."
+ elsif api_client_auth.scopes != ['all']
+ raise "Token exists but has limited scope #{api_client_auth.scopes.inspect}."
end
end
# Check if there is an unexpired superuser token corresponding to this api client
api_client_auth = ApiClientAuthorization.where(
- 'user_id = (?) AND
- api_client_id = (?) AND
+ 'user_id = ? AND
+ api_client_id = ? AND
+ scopes = ? AND
(expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)',
- system_user.id, apiClient.id).first
+ system_user.id, apiClient.id, ['all'].to_yaml).first
# none exist; create one with the supplied token
if !api_client_auth
@cgroup_root = ENV['CRUNCH_CGROUP_ROOT']
@arvados_internal = Rails.configuration.git_internal_dir
- if not File.exists? @arvados_internal
+ if not File.exist? @arvados_internal
$stderr.puts `mkdir -p #{@arvados_internal.shellescape} && git init --bare #{@arvados_internal.shellescape}`
raise "No internal git repository available" unless ($? == 0)
end
# into multiple rows with one hostname each.
`#{cmd} --noheader -o '%N:#{outfmt}'`.each_line do |line|
tokens = line.chomp.split(":", max_fields)
- if (re = tokens[0].match /^(.*?)\[([-,\d]+)\]$/)
+ if (re = tokens[0].match(/^(.*?)\[([-,\d]+)\]$/))
tokens.shift
re[2].split(",").each do |range|
range = range.split("-").collect(&:to_i)
end
def update_node_status
- return unless Server::Application.config.crunch_job_wrapper.to_s.match /^slurm/
+ return unless Server::Application.config.crunch_job_wrapper.to_s.match(/^slurm/)
slurm_status.each_pair do |hostname, slurmdata|
next if @node_state[hostname] == slurmdata
begin
end
usable_nodes << node
if usable_nodes.count >= min_node_count
- return usable_nodes.map { |node| node.hostname }
+ return usable_nodes.map { |n| n.hostname }
end
end
nil
def read_pipes
@running.each do |job_uuid, j|
- job = j[:job]
-
now = Time.now
if now > j[:log_throttle_reset_time]
# It has been more than throttle_period seconds since the last
+$system_user = nil
+$system_group = nil
+$all_users_group = nil
+$anonymous_user = nil
+$anonymous_group = nil
+$anonymous_group_read_permission = nil
+$empty_collection = nil
+
module CurrentApiClient
def current_user
Thread.current[:user]
User.all.collect(&:uuid).each do |user_uuid|
Link.create!(link_class: 'permission',
name: 'can_manage',
- tail_kind: 'arvados#group',
tail_uuid: system_group_uuid,
- head_kind: 'arvados#user',
head_uuid: user_uuid)
end
end
@connection_count = 0
end
+ def send_message(ws, obj)
+ ws.send(Oj.dump(obj, mode: :compat))
+ end
+
# Push out any pending events to the connection +ws+
# +notify_id+ the id of the most recent row in the log table, may be nil
#
logs.select('logs.id').find_each do |l|
if not ws.sent_ids.include?(l.id)
# only send if not a duplicate
- ws.send(Log.find(l.id).as_api_response.to_json)
+ send_message(ws, Log.find(l.id).as_api_response)
end
if not ws.last_log_id.nil?
# record ids only when sending "catchup" messages, not notifies
rescue ArgumentError => e
# There was some kind of user error.
Rails.logger.warn "Error publishing event: #{$!}"
- ws.send ({status: 500, message: $!}.to_json)
+ send_message(ws, {status: 500, message: $!})
ws.close
rescue => e
Rails.logger.warn "Error publishing event: #{$!}"
Rails.logger.warn "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
- ws.send ({status: 500, message: $!}.to_json)
+ send_message(ws, {status: 500, message: $!})
ws.close
# These exceptions typically indicate serious server trouble:
# out of memory issues, database connection problems, etc. Go ahead and
p = (Oj.strict_load event.data).symbolize_keys
filter = Filter.new(p)
rescue Oj::Error => e
- ws.send ({status: 400, message: "malformed request"}.to_json)
+ send_message(ws, {status: 400, message: "malformed request"})
return
end
# Add a filter. This gets the :filters field which is the same
# format as used for regular index queries.
ws.filters << filter
- ws.send ({status: 200, message: 'subscribe ok', filter: p}.to_json)
+ send_message(ws, {status: 200, message: 'subscribe ok', filter: p})
# Send any pending events
push_events ws, nil
else
- ws.send ({status: 403, message: "maximum of #{Rails.configuration.websocket_max_filters} filters allowed per connection"}.to_json)
+ send_message(ws, {status: 403, message: "maximum of #{Rails.configuration.websocket_max_filters} filters allowed per connection"})
end
elsif p[:method] == 'unsubscribe'
len = ws.filters.length
ws.filters.select! { |f| not ((f.filters == p[:filters]) or (f.filters.empty? and p[:filters].nil?)) }
if ws.filters.length < len
- ws.send ({status: 200, message: 'unsubscribe ok'}.to_json)
+ send_message(ws, {status: 200, message: 'unsubscribe ok'})
else
- ws.send ({status: 404, message: 'filter not found'}.to_json)
+ send_message(ws, {status: 404, message: 'filter not found'})
end
else
- ws.send ({status: 400, message: "missing or unrecognized method"}.to_json)
+ send_message(ws, {status: 400, message: "missing or unrecognized method"})
end
rescue => e
Rails.logger.warn "Error handling message: #{$!}"
Rails.logger.warn "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
- ws.send ({status: 500, message: 'error'}.to_json)
+ send_message(ws, {status: 500, message: 'error'})
ws.close
end
end
# Disconnect if no valid API token.
# current_user is included from CurrentApiClient
if not current_user
- ws.send ({status: 401, message: "Valid API token required"}.to_json)
- ws.close
+ send_message(ws, {status: 401, message: "Valid API token required"})
+ # Wait for the handshake to complete before closing the
+ # socket. Otherwise, nginx responds with HTTP 502 Bad gateway,
+ # and the client never sees our real error message.
+ ws.on :open do |event|
+ ws.close
+ end
return
end
# forward them to the thread associated with the connection.
sub = @channel.subscribe do |msg|
if ws.queue.length > Rails.configuration.websocket_max_notify_backlog
- ws.send ({status: 500, message: 'Notify backlog too long'}.to_json)
+ send_message(ws, {status: 500, message: 'Notify backlog too long'})
ws.close
@channel.unsubscribe sub
ws.queue.clear
@mtx.synchronize do
@connection_count -= 1
end
+ ActiveRecord::Base.connection.close
end
end
# has used set_table_name to use an alternate table name from the Rails standard.
# I could not find a perfect way to handle this well, but ActiveRecord::Base.send(:descendants)
# would be a place to start if this ever becomes necessary.
- if attr.match /^[a-z][_a-z0-9]+$/ and
+ if attr.match(/^[a-z][_a-z0-9]+$/) and
model_class.columns.collect(&:name).index(attr) and
['asc','desc'].index direction.downcase
@orders << "#{table_name}.#{attr} #{direction.downcase}"
- elsif attr.match /^([a-z][_a-z0-9]+)\.([a-z][_a-z0-9]+)$/ and
+ elsif attr.match(/^([a-z][_a-z0-9]+)\.([a-z][_a-z0-9]+)$/) and
['asc','desc'].index(direction.downcase) and
ActiveRecord::Base.connection.tables.include?($1) and
$1.classify.constantize.columns.collect(&:name).index($2)
# Any ordering columns must be selected when doing select,
# otherwise it is an SQL error, so filter out invaliding orderings.
@orders.select! { |o|
+ col, dir = o.split
# match select column against order array entry
- @select.select { |s| /^#{table_name}.#{s}( (asc|desc))?$/.match o }.any?
+ @select.select { |s| col == "#{table_name}.#{s}" }.any?
}
end
def salvage_collection_locator_data manifest
locators = []
size = 0
- manifest.scan /(^|[^[:xdigit:]])([[:xdigit:]]{32})((\+\d+)(\+|\b))?/ do |_, hash, _, sizehint, _|
+ manifest.scan(/(^|[^[:xdigit:]])([[:xdigit:]]{32})((\+\d+)(\+|\b))?/) do |_, hash, _, sizehint, _|
if sizehint
locators << hash.downcase + sizehint
size += sizehint.to_i
--- /dev/null
+require 'current_api_client'
+
+module SweepTrashedCollections
+ extend CurrentApiClient
+
+ def self.sweep_now
+ act_as_system_user do
+ Collection.unscoped.
+ where('delete_at is not null and delete_at < statement_timestamp()').
+ destroy_all
+ Collection.unscoped.
+ where('is_trashed = false and trash_at < statement_timestamp()').
+ update_all('is_trashed = true')
+ end
+ end
+
+ def self.sweep_if_stale
+ return if Rails.configuration.trash_sweep_interval <= 0
+ exp = Rails.configuration.trash_sweep_interval.seconds
+ need = false
+ Rails.cache.fetch('SweepTrashedCollections', expires_in: exp) do
+ need = true
+ end
+ if need
+ Thread.new do
+ begin
+ sweep_now
+ ensure
+ ActiveRecord::Base.connection.close
+ end
+ end
+ end
+ end
+end
--- /dev/null
+namespace :config do
+ desc 'Show site configuration'
+ task dump: :environment do
+ puts $application_config.to_yaml
+ end
+end
# load and merge in the environment-specific application config info
# if present, overriding base config parameters as specified
path = File.absolute_path('../../config/arvados-clients.yml', __FILE__)
-if File.exists?(path) then
+if File.exist?(path) then
cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
else
puts "Please create a\n #{path}\n file"
begin
# Get our local gitolite-admin repo up to snuff
- if not File.exists?(gitolite_admin) then
+ if not File.exist?(gitolite_admin) then
ensure_directory(gitolite_tmpdir, 0700)
Dir.chdir(gitolite_tmpdir)
`git clone #{gitolite_url}`
# load and merge in the environment-specific application config info
# if present, overriding base config parameters as specified
path = File.dirname(__FILE__) + '/config/arvados-clients.yml'
-if File.exists?(path) then
+if File.exist?(path) then
cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
else
puts "Please create a\n " + File.dirname(__FILE__) + "/config/arvados-clients.yml\n file"
begin
# Get our local gitolite-admin repo up to snuff
- if not File.exists?(gitolite_admin) then
+ if not File.exist?(gitolite_admin) then
ensure_directory(gitolite_tmpdir, 0700)
Dir.chdir(gitolite_tmpdir)
`git clone #{gitolite_url}`
FactoryGirl.define do
factory :user do
- ignore do
+ transient do
join_groups []
end
after :create do |user, evaluator|
manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
name: collection_to_move_around
+# Note: collections(:expired_collection) fixture finder won't work
+# because it is not in default scope
expired_collection:
uuid: zzzzz-4zz18-mto52zx1s7sn3ih
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
modified_at: 2014-02-03T17:22:54Z
updated_at: 2014-02-03T17:22:54Z
- expires_at: 2001-01-01T00:00:00Z
+ is_trashed: true
+ trash_at: 2001-01-01T00:00:00Z
+ delete_at: 2038-01-01T00:00:00Z
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:expired\n"
name: expired_collection
+trashed_on_next_sweep:
+ uuid: zzzzz-4zz18-4guozfh77ewd2f0
+ portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
+ owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ created_at: 2016-12-07T22:01:00.123456Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2016-12-27T22:01:30.123456Z
+ updated_at: 2016-12-27T22:01:30.123456Z
+ is_trashed: false
+ trash_at: 2016-12-07T22:01:30.123456Z
+ delete_at: 2112-01-01T00:00:00Z
+ manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:expired\n"
+ name: trashed_on_next_sweep
+
+# Note: collections(:deleted_on_next_sweep) fixture finder won't work
+# because it is not in default scope
+deleted_on_next_sweep:
+ uuid: zzzzz-4zz18-3u1p5umicfpqszp
+ portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
+ owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ created_at: 2016-12-07T22:01:00.234567Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2016-12-27T22:01:30.234567Z
+ updated_at: 2016-12-27T22:01:30.234567Z
+ is_trashed: true
+ trash_at: 2016-12-07T22:01:30.234567Z
+ delete_at: 2016-12-27T22:01:30.234567Z
+ manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:expired\n"
+ name: deleted_on_next_sweep
+
collection_expires_in_future:
uuid: zzzzz-4zz18-padkqo7yb8d9i3j
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
modified_at: 2014-02-03T17:22:54Z
updated_at: 2014-02-03T17:22:54Z
- expires_at: 2038-01-01T00:00:00Z
+ trash_at: 2038-01-01T00:00:00Z
+ delete_at: 2038-03-01T00:00:00Z
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:expired\n"
name: collection_expires_in_future
output_path: test
command: ["echo", "hello"]
container_uuid: zzzzz-dz642-compltcontainer
+ log_uuid: zzzzz-4zz18-y9vne9npefyxh8g
+ output_uuid: zzzzz-4zz18-znfnqtbbv4spc3w
runtime_constraints:
vcpus: 1
ram: 123
log: zzzzz-4zz18-4en62shvi99lxd4
output: b519d9cb706a29fc7ea24dbea2f05851+93
script_parameters_digest: 02a085407e751d00b5dc88f1bd5e8247
+ started_at: <%= 10.minute.ago.to_s(:db) %>
+ finished_at: <%= 5.minute.ago.to_s(:db) %>
job_in_publicly_accessible_project_but_other_objects_elsewhere:
uuid: zzzzz-8i9sb-jyq01muyhgr4ofj
dataclass: Collection
title: "Foo/bar pair"
description: "Provide a collection containing at least two files."
+
+workflow_with_input_defaults:
+ uuid: zzzzz-p5p6p-aox0k0ofxrystg2
+ owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+ created_at: 2014-04-14 12:35:04 -0400
+ updated_at: 2014-04-14 12:35:04 -0400
+ modified_at: 2014-04-14 12:35:04 -0400
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ name: Pipeline with default input specifications
+ components:
+ part-one:
+ script: foo
+ script_version: master
+ script_parameters:
+ ex_string:
+ required: true
+ dataclass: string
+ ex_string_def:
+ required: true
+ dataclass: string
+ default: hello-testing-123
\ No newline at end of file
inputBinding:
position: 1
outputs: []
+
+workflow_with_input_defaults:
+ uuid: zzzzz-7fd4e-validwithinput2
+ owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
+ name: Workflow with default input specifications
+ description: this workflow has inputs specified
+ created_at: <%= 1.minute.ago.to_s(:db) %>
+ definition: |
+ cwlVersion: v1.0
+ class: CommandLineTool
+ baseCommand:
+ - echo
+ inputs:
+ - type: string
+ id: ex_string
+ - type: string
+ id: ex_string_def
+ default: hello-testing-123
+ outputs: []
get :index, search_params
assert_response :success
got_tokens = JSON.parse(@response.body)['items']
- .map { |auth| auth['api_token'] }
+ .map { |a| a['api_token'] }
assert_equal(expected_tokens.sort, got_tokens.sort,
"wrong results for #{search_params.inspect}")
end
require 'test_helper'
class Arvados::V1::CollectionsControllerTest < ActionController::TestCase
+ include DbCurrentTime
+
+ PERM_TOKEN_RE = /\+A[[:xdigit:]]+@[[:xdigit:]]{8}\b/
def permit_unsigned_manifests isok=true
# Set security model for the life of a test.
def assert_signed_manifest manifest_text, label=''
assert_not_nil manifest_text, "#{label} manifest_text was nil"
manifest_text.scan(/ [[:xdigit:]]{32}\S*/) do |tok|
- assert_match(/\+A[[:xdigit:]]+@[[:xdigit:]]{8}\b/, tok,
+ assert_match(PERM_TOKEN_RE, tok,
"Locator in #{label} manifest_text was not signed")
end
end
+ def assert_unsigned_manifest resp, label=''
+ txt = resp['unsigned_manifest_text']
+ assert_not_nil(txt, "#{label} unsigned_manifest_text was nil")
+ locs = 0
+ txt.scan(/ [[:xdigit:]]{32}\S*/) do |tok|
+ locs += 1
+ refute_match(PERM_TOKEN_RE, tok,
+ "Locator in #{label} unsigned_manifest_text was signed: #{tok}")
+ end
+ return locs
+ end
+
test "should get index" do
authorize_with :active
get :index
"basic Collections index included manifest_text")
end
- test "collections.get returns signed locators" do
+ test "collections.get returns signed locators, and no unsigned_manifest_text" do
permit_unsigned_manifests
authorize_with :active
get :show, {id: collections(:foo_file).uuid}
assert_response :success
assert_signed_manifest json_response['manifest_text'], 'foo_file'
+ refute_includes json_response, 'unsigned_manifest_text'
end
test "index with manifest_text selected returns signed locators" do
assert(assigns(:objects).andand.any?,
"no Collections returned for index with columns selected")
json_response["items"].each do |coll|
- assert_equal(columns, columns & coll.keys,
+ assert_equal(coll.keys - ['kind'], columns,
"Collections index did not respect selected columns")
assert_signed_manifest coll['manifest_text'], coll['uuid']
end
end
+ test "index with unsigned_manifest_text selected returns only unsigned locators" do
+ authorize_with :active
+ get :index, select: ['unsigned_manifest_text']
+ assert_response :success
+ assert_operator json_response["items"].count, :>, 0
+ locs = 0
+ json_response["items"].each do |coll|
+ assert_equal(coll.keys - ['kind'], ['unsigned_manifest_text'],
+ "Collections index did not respect selected columns")
+ locs += assert_unsigned_manifest coll, coll['uuid']
+ end
+ assert_operator locs, :>, 0, "no locators found in any manifests"
+ end
+
+ test 'index without select returns everything except manifest' do
+ authorize_with :active
+ get :index
+ assert_response :success
+ assert json_response['items'].any?
+ json_response['items'].each do |coll|
+ assert_includes(coll.keys, 'uuid')
+ assert_includes(coll.keys, 'name')
+ assert_includes(coll.keys, 'created_at')
+ refute_includes(coll.keys, 'manifest_text')
+ end
+ end
+
+ ['', nil, false, 'null'].each do |select|
+ test "index with select=#{select.inspect} returns everything except manifest" do
+ authorize_with :active
+ get :index, select: select
+ assert_response :success
+ assert json_response['items'].any?
+ json_response['items'].each do |coll|
+ assert_includes(coll.keys, 'uuid')
+ assert_includes(coll.keys, 'name')
+ assert_includes(coll.keys, 'created_at')
+ refute_includes(coll.keys, 'manifest_text')
+ end
+ end
+ end
+
+ [["uuid"],
+ ["uuid", "manifest_text"],
+ '["uuid"]',
+ '["uuid", "manifest_text"]'].each do |select|
+ test "index with select=#{select.inspect} returns no name" do
+ authorize_with :active
+ get :index, select: select
+ assert_response :success
+ assert json_response['items'].any?
+ json_response['items'].each do |coll|
+ refute_includes(coll.keys, 'name')
+ end
+ end
+ end
+
[0,1,2].each do |limit|
test "get index with limit=#{limit}" do
authorize_with :active
ensure_unique_name: true
}
assert_response :success
- assert_equal 'owned_by_active (2)', json_response['name']
+ assert_match /^owned_by_active \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
end
end
[2**8, :success],
[2**18, 422],
].each do |description_size, expected_response|
- test "create collection with description size #{description_size}
+ # Descriptions are not part of search indexes. Skip until
+ # full-text search is implemented, at which point replace with a
+ # search in description.
+ skip "create collection with description size #{description_size}
and expect response #{expected_response}" do
- skip "(Descriptions are not part of search indexes. Skip until full-text search
- is implemented, at which point replace with a search in description.)"
-
authorize_with :active
description = 'here is a collection with a very large description'
assert_response 200
end
end
+
+ test 'get trashed collection with include_trash' do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with :active
+ get :show, {
+ id: uuid,
+ include_trash: true,
+ }
+ assert_response 200
+ end
+
+ test 'get trashed collection without include_trash' do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with :active
+ get :show, {
+ id: uuid,
+ }
+ assert_response 404
+ end
+
+ test 'trash collection using http DELETE verb' do
+ uuid = collections(:collection_owned_by_active).uuid
+ authorize_with :active
+ delete :destroy, {
+ id: uuid,
+ }
+ assert_response 200
+ c = Collection.unscoped.find_by_uuid(uuid)
+ assert_operator c.trash_at, :<, db_current_time
+ assert_equal c.delete_at, c.trash_at + Rails.configuration.blob_signature_ttl
+ end
+
+ test 'delete long-trashed collection immediately using http DELETE verb' do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with :active
+ delete :destroy, {
+ id: uuid,
+ }
+ assert_response 200
+ c = Collection.unscoped.find_by_uuid(uuid)
+ assert_operator c.trash_at, :<, db_current_time
+ assert_operator c.delete_at, :<, db_current_time
+ end
+
+ ['zzzzz-4zz18-mto52zx1s7sn3ih', # expired_collection
+ :empty_collection_name_in_active_user_home_project,
+ ].each do |fixture|
+ test "trash collection #{fixture} via trash action with grace period" do
+ if fixture.is_a? String
+ uuid = fixture
+ else
+ uuid = collections(fixture).uuid
+ end
+ authorize_with :active
+ time_before_trashing = db_current_time
+ post :trash, {
+ id: uuid,
+ }
+ assert_response 200
+ c = Collection.unscoped.find_by_uuid(uuid)
+ assert_operator c.trash_at, :<, db_current_time
+ assert_operator c.delete_at, :>=, time_before_trashing + Rails.configuration.default_trash_lifetime
+ end
+ end
end
--- /dev/null
+require 'test_helper'
+
+class Arvados::V1::ContainerRequestsControllerTest < ActionController::TestCase
+ test 'create with scheduling parameters' do
+ authorize_with :system_user
+
+ sp = {'partitions' => ['test1', 'test2']}
+ post :create, {
+ container_request: {
+ command: ['echo', 'hello'],
+ container_image: 'test',
+ output_path: 'test',
+ scheduling_parameters: sp,
+ },
+ }
+ assert_response :success
+
+ cr = JSON.parse(@response.body)
+ assert_not_nil cr, 'Expected container request'
+ assert_equal sp, cr['scheduling_parameters']
+ end
+end
filters: [['uuid', '@@', 'abcdef']],
}
assert_response 422
- assert_match /not supported/, json_response['errors'].join(' ')
+ assert_match(/not supported/, json_response['errors'].join(' '))
end
test 'difficult characters in full text search' do
filters: [['any', '@@', ['abc', 'def']]],
}
assert_response 422
- assert_match /not supported/, json_response['errors'].join(' ')
+ assert_match(/not supported/, json_response['errors'].join(' '))
end
test 'api responses provide timestamps with nanoseconds' do
%w(created_at modified_at).each do |attr|
# Pass fixtures with null timestamps.
next if item[attr].nil?
- assert_match /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d.\d{9}Z$/, item[attr]
+ assert_match(/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d.\d{9}Z$/, item[attr])
end
end
end
assert_equal 0, json_response['items_available']
end
- def check_project_contents_response
+ def check_project_contents_response disabled_kinds=[]
assert_response :success
assert_operator 2, :<=, json_response['items_available']
assert_operator 2, :<=, json_response['items'].count
kinds = json_response['items'].collect { |i| i['kind'] }.uniq
- expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job'
+ expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds
assert_equal expect_kinds, (expect_kinds & kinds)
json_response['items'].each do |i|
"group#contents returned a non-project group")
end
end
+
+ disabled_kinds.each do |d|
+ assert_equal true, !kinds.include?(d)
+ end
end
test 'get group-owned objects' do
assert_not_equal(new_project['uuid'],
groups(:aproject).uuid,
"create returned same uuid as existing project")
- assert_equal(new_project['name'],
- 'A Project (2)',
- "new project name '#{new_project['name']}' was expected to be 'A Project (2)'")
+ assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/,
+ new_project['name'])
end
test "unsharing a project results in hiding it from previously shared user" do
end
end
end
+
+ test 'get contents with jobs and pipeline instances disabled' do
+ Rails.configuration.disable_api_methods = ['jobs.index', 'pipeline_instances.index']
+
+ authorize_with :active
+ get :contents, {
+ id: groups(:aproject).uuid,
+ format: :json,
+ }
+ check_project_contents_response %w'arvados#pipelineInstance arvados#job'
+ end
end
'server should correct bogus cancelled_at ' +
job['cancelled_at'])
assert_equal(true,
- File.exists?(Rails.configuration.crunch_refresh_trigger),
+ File.exist?(Rails.configuration.crunch_refresh_trigger),
'trigger file should be created when job is cancelled')
end
assert_response 404
end
- test "retrieve all permissions using generic links index api" do
- skip "(not implemented)"
+ # not implemented
+ skip "retrieve all permissions using generic links index api" do
# Links.readable_by() does not return the full set of permission
# links that are visible to a user (i.e., all permission links
# whose head_uuid references an object for which the user has
end
test "get_all_permissions takes into account is_active flag" do
- r = nil
act_as_user users(:active) do
- r = Repository.create! name: 'active/testrepo'
+ Repository.create! name: 'active/testrepo'
end
act_as_system_user do
u = users(:active)
u = User.find_by_uuid(user_uuid)
if perms['can_read']
assert u.can? read: repo['uuid']
- assert_match /R/, perms['gitolite_permissions']
+ assert_match(/R/, perms['gitolite_permissions'])
else
- refute_match /R/, perms['gitolite_permissions']
+ refute_match(/R/, perms['gitolite_permissions'])
end
if perms['can_write']
assert u.can? write: repo['uuid']
- assert_match /RW\+/, perms['gitolite_permissions']
+ assert_match(/RW\+/, perms['gitolite_permissions'])
else
- refute_match /W/, perms['gitolite_permissions']
+ refute_match(/W/, perms['gitolite_permissions'])
end
if perms['can_manage']
assert u.can? manage: repo['uuid']
- assert_match /RW\+/, perms['gitolite_permissions']
+ assert_match(/RW\+/, perms['gitolite_permissions'])
end
end
end
get :index
assert_response :success
discovery_doc = JSON.parse(@response.body)
- assert_match /^[0-9a-f]+(-modified)?$/, discovery_doc['source_version']
+ assert_match(/^[0-9a-f]+(-modified)?$/, discovery_doc['source_version'])
end
test "discovery document overrides source_version with config" do
active_user = User.find_by_uuid(users(:active).uuid)
readable_groups = active_user.groups_i_can(:read)
- all_users_group = Group.all.collect(&:uuid).select { |g| g.match /-f+$/ }
+ all_users_group = Group.all.collect(&:uuid).select { |g| g.match(/-f+$/) }
refute_includes(readable_groups, all_users_group,
"active user can read All Users group after being deactivated")
assert_equal(false, active_user.is_invited,
end
def verify_num_links (original_links, expected_additional_links)
- links_now = Link.all
assert_equal expected_additional_links, Link.all.size-original_links.size,
"Expected #{expected_additional_links.inspect} more links"
end
def find_obj_in_resp (response_items, object_type, head_kind=nil)
return_obj = nil
- response_items
response_items.each { |x|
if !x
next
test "groups is an empty list by default" do
get_logins_for(:testvm2)
active_login = find_login(:active)
- perm = links(:active_can_login_to_testvm2)
assert_equal([], active_login["groups"])
end
end
group = Group.where(name: 'All users').select do |g|
- g[:uuid].match /-f+$/
+ g[:uuid].match(/-f+$/)
end.first
group_read_perms = Link.where(tail_uuid: uuid,
head_uuid: group[:uuid],
:filters => ['uuid', '=', 'ad02e37b6a7f45bbe2ead3c29a109b8a+54'].to_json
}, auth(:active)
assert_response 422
- assert_match /nvalid element.*not an array/, json_response['errors'].join(' ')
+ assert_match(/nvalid element.*not an array/, json_response['errors'].join(' '))
end
test "get index with invalid filters (unsearchable column) responds 422" do
:filters => [['this_column_does_not_exist', '=', 'bogus']].to_json
}, auth(:active)
assert_response 422
- assert_match /nvalid attribute/, json_response['errors'].join(' ')
+ assert_match(/nvalid attribute/, json_response['errors'].join(' '))
end
test "get index with invalid filters (invalid operator) responds 422" do
:filters => [['uuid', ':-(', 'displeased']].to_json
}, auth(:active)
assert_response 422
- assert_match /nvalid operator/, json_response['errors'].join(' ')
+ assert_match(/nvalid operator/, json_response['errors'].join(' '))
end
test "get index with invalid filters (invalid operand type) responds 422" do
:filters => [['uuid', '=', {foo: 'bar'}]].to_json
}, auth(:active)
assert_response 422
- assert_match /nvalid operand type/, json_response['errors'].join(' ')
+ assert_match(/nvalid operand type/, json_response['errors'].join(' '))
end
test "get index with where= (empty string)" do
:select => ['bogus'].to_json
}, auth(:active)
assert_response 422
- assert_match /Invalid attribute.*bogus/, json_response['errors'].join(' ')
+ assert_match(/Invalid attribute.*bogus/, json_response['errors'].join(' '))
end
test "get index with select= (invalid attribute type) responds 422" do
:select => [['bogus']].to_json
}, auth(:active)
assert_response 422
- assert_match /Invalid attribute.*bogus/, json_response['errors'].join(' ')
+ assert_match(/Invalid attribute.*bogus/, json_response['errors'].join(' '))
end
test "controller 404 response is json" do
assert_response :success
assert_equal true, json_response['manifest_text'].include?('file4_in_subdir4.txt')
- created = json_response
-
# search using the filename
search_using_full_text_search 'subdir2', 0
search_using_full_text_search 'subdir2:*', 1
class CollectionsApiPerformanceTest < ActionDispatch::IntegrationTest
include ManifestExamples
- test "crud cycle for a collection with a big manifest" do
- slow_test
+ slow_test "crud cycle for a collection with a big manifest" do
bigmanifest = time_block 'make example' do
make_manifest(streams: 100,
files_per_stream: 100,
end
end
- test "memory usage" do
- slow_test
+ slow_test "memory usage" do
hugemanifest = make_manifest(streams: 1,
files_per_stream: 2000,
blocks_per_file: 200,
def assert_no_cors_headers
response.headers.keys.each do |h|
- assert_no_match /^Access-Control-/i, h
+ assert_no_match(/^Access-Control-/i, h)
end
end
end
class DatabaseResetTest < ActionDispatch::IntegrationTest
self.use_transactional_fixtures = false
- test "reset fails when Rails.env != 'test'" do
- slow_test
+ slow_test "reset fails when Rails.env != 'test'" do
rails_env_was = Rails.env
begin
Rails.env = 'production'
assert_response 403
end
- test "database reset doesn't break basic CRUD operations" do
- slow_test
+ slow_test "database reset doesn't break basic CRUD operations" do
active_auth = auth(:active)
admin_auth = auth(:admin)
assert_response 404
end
- test "roll back database change" do
- slow_test
+ slow_test "roll back database change" do
active_auth = auth(:active)
admin_auth = auth(:admin)
end
end
+ test "select with default order" do
+ get "/arvados/v1/links", {format: :json, select: ['uuid']}, auth(:admin)
+ assert_response :success
+ uuids = json_response['items'].collect { |i| i['uuid'] }
+ assert_equal uuids, uuids.sort
+ end
+
def assert_link_classes_ascend(current_class, prev_class)
# Databases and Ruby don't always agree about string ordering with
# punctuation. If the strings aren't ascending normally, check
(repos.collect(&:name) +
vm_links.collect { |link| link.properties['username'] }
).each do |name|
- r = name.match /^(.{#{prefix.length}})(\d+)$/
+ r = name.match(/^(.{#{prefix.length}})(\d+)$/)
assert_not_nil r, "#{name.inspect} does not match {prefix}\\d+"
assert_equal(prefix, r[1],
"#{name.inspect} was not {#{prefix.inspect} plus digits}")
require 'test_helper'
-require 'websocket_runner'
require 'oj'
require 'database_cleaner'
DatabaseCleaner.clean
end
- def ws_helper (token = nil, timeout = true)
+ def self.startup
+ s = TCPServer.new('0.0.0.0', 0)
+ @@port = s.addr[1]
+ s.close
+ @@pidfile = "tmp/pids/passenger.#{@@port}.pid"
+ DatabaseCleaner.start
+ Dir.chdir(Rails.root) do |apidir|
+ # Only passenger seems to be able to run the websockets server
+ # successfully.
+ _system('passenger', 'start', '-d',
+ "-p#{@@port}",
+ "--log-file", "/dev/stderr",
+ "--pid-file", @@pidfile)
+ timeout = Time.now.tv_sec + 10
+ begin
+ sleep 0.2
+ begin
+ server_pid = IO.read(@@pidfile).to_i
+ good_pid = (server_pid > 0) and (Process.kill(0, pid) rescue false)
+ rescue Errno::ENOENT
+ good_pid = false
+ end
+ end while (not good_pid) and (Time.now.tv_sec < timeout)
+ if not good_pid
+ raise RuntimeError, "could not find API server Rails pid"
+ end
+ STDERR.puts "Started websocket server on port #{@@port} with pid #{server_pid}"
+ end
+ end
+
+ def self.shutdown
+ Dir.chdir(Rails.root) do
+ _system('passenger', 'stop', "-p#{@@port}",
+ "--pid-file", @@pidfile)
+ end
+ # DatabaseCleaner leaves the database empty. Prefer to leave it full.
+ dc = DatabaseController.new
+ dc.define_singleton_method :render do |*args| end
+ dc.reset
+ end
+
+ def self._system(*cmd)
+ Bundler.with_clean_env do
+ env = {
+ 'ARVADOS_WEBSOCKETS' => 'ws-only',
+ 'RAILS_ENV' => 'test',
+ }
+ if not system(env, *cmd)
+ raise RuntimeError, "Command exited #{$?}: #{cmd.inspect}"
+ end
+ end
+ end
+
+ def ws_helper(token: nil, timeout: 8)
opened = false
close_status = nil
too_long = false
- EM.run {
+ EM.run do
if token
- ws = Faye::WebSocket::Client.new("ws://localhost:#{WEBSOCKET_PORT}/websocket?api_token=#{api_client_authorizations(token).api_token}")
+ ws = Faye::WebSocket::Client.new("ws://localhost:#{@@port}/websocket?api_token=#{api_client_authorizations(token).api_token}")
else
- ws = Faye::WebSocket::Client.new("ws://localhost:#{WEBSOCKET_PORT}/websocket")
+ ws = Faye::WebSocket::Client.new("ws://localhost:#{@@port}/websocket")
end
ws.on :open do |event|
opened = true
if timeout
- EM::Timer.new 8 do
+ EM::Timer.new(timeout) do
too_long = true if close_status.nil?
EM.stop_event_loop
end
end
end
+ ws.on :error do |event|
+ STDERR.puts "websocket client error: #{event.inspect}"
+ end
+
ws.on :close do |event|
close_status = [:close, event.code, event.reason]
EM.stop_event_loop
end
yield ws
- }
+ end
assert opened, "Should have opened web socket"
assert (not too_long), "Test took too long"
assert_equal 401, status
end
-
test "connect, subscribe and get response" do
status = nil
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
end
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
end
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
end
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
end
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#specimen']]}.to_json)
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#trait'], ['event_type', '=', 'update']]}.to_json)
end
test "connect, subscribe, ask events starting at seq num" do
state = 1
- human = nil
- human_ev_uuid = nil
authorize_with :active
l1 = nil
l2 = nil
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe', last_log_id: lastid}.to_json)
end
assert_equal expect_next_logs[1].object_uuid, l2
end
- test "connect, subscribe, get event, unsubscribe" do
- slow_test
+ slow_test "connect, subscribe, get event, unsubscribe" do
state = 1
spec = nil
spec_ev_uuid = nil
- filter_id = nil
authorize_with :active
- ws_helper :active, false do |ws|
+ ws_helper(token: :active, timeout: false) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
EM::Timer.new 3 do
assert_equal spec.uuid, spec_ev_uuid
end
- test "connect, subscribe, get event, unsubscribe with filter" do
- slow_test
+ slow_test "connect, subscribe, get event, unsubscribe with filter" do
state = 1
spec = nil
spec_ev_uuid = nil
authorize_with :active
- ws_helper :active, false do |ws|
+ ws_helper(token: :active, timeout: false) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
EM::Timer.new 6 do
end
- test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
- slow_test
+ slow_test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
state = 1
spec = nil
spec_ev_uuid = nil
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
end
assert_equal human.uuid, human_ev_uuid
end
-
-
- test "connected, not subscribed, no event" do
- slow_test
+ slow_test "connected, not subscribed, no event" do
authorize_with :active
- ws_helper :active, false do |ws|
+ ws_helper(token: :active, timeout: false) do |ws|
ws.on :open do |event|
EM::Timer.new 1 do
Specimen.create
end
end
- test "connected, not authorized to see event" do
- slow_test
+ slow_test "connected, not authorized to see event" do
state = 1
authorize_with :admin
- ws_helper :active, false do |ws|
+ ws_helper(token: :active, timeout: false) do |ws|
ws.on :open do |event|
ws.send ({method: 'subscribe'}.to_json)
test "connect, try bogus method" do
status = nil
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({method: 'frobnabble'}.to_json)
end
test "connect, missing method" do
status = nil
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send ({fizzbuzz: 'frobnabble'}.to_json)
end
test "connect, send malformed request" do
status = nil
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
ws.send '<XML4EVER></XML4EVER>'
end
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
(1..17).each do |i|
ws.send ({method: 'subscribe', filters: [['object_uuid', '=', i]]}.to_json)
end
- test "connect, subscribe, lots of events" do
- slow_test
+ slow_test "connect, subscribe, lots of events" do
state = 1
event_count = 0
log_start = Log.order(:id).last.id
authorize_with :active
- ws_helper :active, false do |ws|
+ ws_helper(token: :active, timeout: false) do |ws|
EM::Timer.new 45 do
# Needs a longer timeout than the default
ws.close
assert_equal 200, d["status"]
ActiveRecord::Base.transaction do
(1..202).each do
- spec = Specimen.create
+ Specimen.create
end
end
state = 2
test "connect, subscribe with invalid filter" do
state = 1
- human = nil
- human_ev_uuid = nil
authorize_with :active
- ws_helper :active do |ws|
+ ws_helper(token: :active) do |ws|
ws.on :open do |event|
# test that #6451 is fixed (invalid filter crashes websockets)
ws.send ({method: 'subscribe', filters: [['object_blarg', 'is_a', 'arvados#human']]}.to_json)
when 1
assert_equal 200, d["status"]
Specimen.create
- human = Human.create
+ Human.create
state = 2
when 2
assert_equal 500, d["status"]
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
-require 'mocha/mini_test'
+require 'mocha'
module ArvadosTestSupport
def json_response
def restore_configuration
# Restore configuration settings changed during tests
$application_config.each do |k,v|
- if k.match /^[^.]*$/
+ if k.match(/^[^.]*$/)
Rails.configuration.send (k + '='), v
end
end
"HTTP_AUTHORIZATION" => "OAuth2 #{t}")
end
- def slow_test
- skip "RAILS_TEST_SHORT is set" unless (ENV['RAILS_TEST_SHORT'] || '').empty?
+ def self.skip_slow_tests?
+ !(ENV['RAILS_TEST_SHORT'] || '').empty?
end
+
+ def self.skip(*args, &block)
+ end
+
+ def self.slow_test(name, &block)
+ define_method(name, block) unless skip_slow_tests?
+ end
+
+ alias_method :skip, :omit
end
class ActionController::TestCase
super action, *args
end
end
+
+ def self.suite
+ s = super
+ def s.run(*args)
+ @test_case.startup()
+ begin
+ super
+ ensure
+ @test_case.shutdown()
+ end
+ end
+ s
+ end
+ def self.startup; end
+ def self.shutdown; end
end
class ActionDispatch::IntegrationTest
end
end
- test 'override with configuration' do
+ test 'override with configuration "foobar"' do
Rails.configuration.source_version = 'foobar'
assert_equal 'foobar', AppVersion.hash
+ end
+
+ test 'override with configuration false' do
Rails.configuration.source_version = false
assert_not_equal 'foobar', AppVersion.hash
end
test 'override with file' do
path = Rails.root.join 'git-commit.version'
- assert(!File.exists?(path),
+ assert(!File.exist?(path),
"Packaged version file found in source tree: #{path}")
begin
File.open(path, 'w') do |f|
end
end
+ test "full text search index exists on models" do
+ fts_tables = ["collections", "container_requests", "groups", "jobs",
+ "pipeline_instances", "pipeline_templates", "workflows"]
+ fts_tables.each do |table|
+ table_class = table.classify.constantize
+ if table_class.respond_to?('full_text_searchable_columns')
+ fts_index_columns = table_class.full_text_searchable_columns
+ index_columns = nil
+ indexes = ActiveRecord::Base.connection.indexes(table)
+ fts_index_by_columns = indexes.select do |index|
+ if index.columns.first.match(/to_tsvector/)
+ index_columns = index.columns.first.scan(/\((?<columns>[A-Za-z_]+)\,/).flatten!
+ index_columns.sort == fts_index_columns.sort
+ else
+ false
+ end
+ end
+ assert !fts_index_by_columns.empty?, "#{table} has no FTS index with columns #{fts_index_columns}. Instead found FTS index with columns #{index_columns}"
+ end
+ end
+ end
+
test "selectable_attributes includes database attributes" do
assert_includes(Job.selectable_attributes, "success")
end
ak2 = AuthorizedKey.new(name: "bar", public_key: TEST_KEY, authorized_user_uuid: u2.uuid)
refute ak2.valid?
refute ak2.save
- assert_match /already exists/, ak2.errors.full_messages.to_s
+ assert_match(/already exists/, ak2.errors.full_messages.to_s)
end
end
end
# "crrud" == "create read render update delete", not a typo
- test "crrud cycle for a collection with a big manifest)" do
- slow_test
+ slow_test "crrud cycle for a collection with a big manifest)" do
bigmanifest = time_block 'make example' do
make_manifest(streams: 100,
files_per_stream: 100,
c.signed_manifest_text
end
time_block 'sign + render' do
- resp = c.as_api_response(nil)
+ c.as_api_response(nil)
end
loc = Blob.sign_locator(Digest::MD5.hexdigest('foo') + '+3',
api_token: api_token(:active))
require 'test_helper'
+require 'sweep_trashed_collections'
class CollectionTest < ActiveSupport::TestCase
include DbCurrentTime
c = create_collection "f\xc8o", Encoding::UTF_8
assert !c.valid?
assert_equal [:manifest_text], c.errors.messages.keys
- assert_match /UTF-8/, c.errors.messages[:manifest_text].first
+ assert_match(/UTF-8/, c.errors.messages[:manifest_text].first)
end
end
c = create_collection "f\xc8o", Encoding::ASCII_8BIT
assert !c.valid?
assert_equal [:manifest_text], c.errors.messages.keys
- assert_match /UTF-8/, c.errors.messages[:manifest_text].first
+ assert_match(/UTF-8/, c.errors.messages[:manifest_text].first)
end
end
assert c.valid?
created_file_names = c.file_names
assert created_file_names
- assert_match /foo.txt/, c.file_names
+ assert_match(/foo.txt/, c.file_names)
c.update_attribute 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo2.txt\n"
assert_not_equal created_file_names, c.file_names
- assert_match /foo2.txt/, c.file_names
+ assert_match(/foo2.txt/, c.file_names)
end
end
assert c.valid?
assert c.file_names
- assert_match /veryverylongfilename0000000000001.txt/, c.file_names
- assert_match /veryverylongfilename0000000000002.txt/, c.file_names
+ assert_match(/veryverylongfilename0000000000001.txt/, c.file_names)
+ assert_match(/veryverylongfilename0000000000002.txt/, c.file_names)
if not allow_truncate
- assert_match /veryverylastfilename/, c.file_names
- assert_match /laststreamname/, c.file_names
+ assert_match(/veryverylastfilename/, c.file_names)
+ assert_match(/laststreamname/, c.file_names)
end
end
end
end
end
- test 'signature expiry does not exceed expires_at' do
+ test 'signature expiry does not exceed trash_at' do
act_as_user users(:active) do
t0 = db_current_time
c = Collection.create!(manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:x\n", name: 'foo')
- c.update_attributes! expires_at: (t0 + 1.hours)
+ c.update_attributes! trash_at: (t0 + 1.hours)
c.reload
sig_exp = /\+A[0-9a-f]{40}\@([0-9]+)/.match(c.signed_manifest_text)[1].to_i
assert_operator sig_exp.to_i, :<=, (t0 + 1.hours).to_i
act_as_user users(:active) do
c = Collection.create!(manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:x\n",
name: 'foo',
- expires_at: db_current_time + 1.years)
+ trash_at: db_current_time + 1.years)
sig_exp = /\+A[0-9a-f]{40}\@([0-9]+)/.match(c.signed_manifest_text)[1].to_i
expect_max_sig_exp = db_current_time.to_i + Rails.configuration.blob_signature_ttl
- assert_operator c.expires_at.to_i, :>, expect_max_sig_exp
+ assert_operator c.trash_at.to_i, :>, expect_max_sig_exp
assert_operator sig_exp.to_i, :<=, expect_max_sig_exp
end
end
uuid = c.uuid
# mark collection as expired
- c.update_attribute 'expires_at', Time.new.strftime("%Y-%m-%d")
+ c.update_attributes!(trash_at: Time.new.strftime("%Y-%m-%d"))
c = Collection.where(uuid: uuid)
assert_empty c, 'Should not be able to find expired collection'
end
end
+ test 'trash_at cannot be set too far in the past' do
+ act_as_user users(:active) do
+ t0 = db_current_time
+ c = Collection.create!(manifest_text: '', name: 'foo')
+ c.update_attributes! trash_at: (t0 - 2.weeks)
+ c.reload
+ assert_operator c.trash_at, :>, t0
+ end
+ end
+
+ [['trash-to-delete interval negative',
+ :collection_owned_by_active,
+ {trash_at: Time.now+2.weeks, delete_at: Time.now},
+ {state: :invalid}],
+ ['trash-to-delete interval too short',
+ :collection_owned_by_active,
+ {trash_at: Time.now+3.days, delete_at: Time.now+7.days},
+ {state: :invalid}],
+ ['trash-to-delete interval ok',
+ :collection_owned_by_active,
+ {trash_at: Time.now, delete_at: Time.now+15.days},
+ {state: :trash_now}],
+ ['trash-to-delete interval short, but far enough in future',
+ :collection_owned_by_active,
+ {trash_at: Time.now+13.days, delete_at: Time.now+15.days},
+ {state: :trash_future}],
+ ['trash by setting is_trashed bool',
+ :collection_owned_by_active,
+ {is_trashed: true},
+ {state: :trash_now}],
+ ['trash in future by setting just trash_at',
+ :collection_owned_by_active,
+ {trash_at: Time.now+1.week},
+ {state: :trash_future}],
+ ['trash in future by setting trash_at and delete_at',
+ :collection_owned_by_active,
+ {trash_at: Time.now+1.week, delete_at: Time.now+4.weeks},
+ {state: :trash_future}],
+ ['untrash by clearing is_trashed bool',
+ :expired_collection,
+ {is_trashed: false},
+ {state: :not_trash}],
+ ].each do |test_name, fixture_name, updates, expect|
+ test test_name do
+ act_as_user users(:active) do
+ min_exp = (db_current_time +
+ Rails.configuration.blob_signature_ttl.seconds)
+ if fixture_name == :expired_collection
+ # Fixture-finder shorthand doesn't find trashed collections
+ # because they're not in the default scope.
+ c = Collection.unscoped.find_by_uuid('zzzzz-4zz18-mto52zx1s7sn3ih')
+ else
+ c = collections(fixture_name)
+ end
+ updates_ok = c.update_attributes(updates)
+ expect_valid = expect[:state] != :invalid
+ assert_equal updates_ok, expect_valid, c.errors.full_messages.to_s
+ case expect[:state]
+ when :invalid
+ refute c.valid?
+ when :trash_now
+ assert c.is_trashed
+ assert_not_nil c.trash_at
+ assert_operator c.trash_at, :<=, db_current_time
+ assert_not_nil c.delete_at
+ assert_operator c.delete_at, :>=, min_exp
+ when :trash_future
+ refute c.is_trashed
+ assert_not_nil c.trash_at
+ assert_operator c.trash_at, :>, db_current_time
+ assert_not_nil c.delete_at
+ assert_operator c.delete_at, :>=, c.trash_at
+ # Currently this minimum interval is needed to prevent early
+ # garbage collection:
+ assert_operator c.delete_at, :>=, min_exp
+ when :not_trash
+ refute c.is_trashed
+ assert_nil c.trash_at
+ assert_nil c.delete_at
+ else
+ raise "bad expect[:state]==#{expect[:state].inspect} in test case"
+ end
+ end
+ end
+ end
+
+ test 'default trash interval > blob signature ttl' do
+ Rails.configuration.default_trash_lifetime = 86400 * 21 # 3 weeks
+ start = db_current_time
+ act_as_user users(:active) do
+ c = Collection.create!(manifest_text: '', name: 'foo')
+ c.update_attributes!(trash_at: start + 86400.seconds)
+ assert_operator c.delete_at, :>=, start + (86400*22).seconds
+ assert_operator c.delete_at, :<, start + (86400*22 + 30).seconds
+ c.destroy
+
+ c = Collection.create!(manifest_text: '', name: 'foo')
+ c.update_attributes!(is_trashed: true)
+ assert_operator c.delete_at, :>=, start + (86400*21).seconds
+ end
+ end
+
test "find_all_for_docker_image resolves names that look like hashes" do
coll_list = Collection.
find_all_for_docker_image('a' * 64, nil, [users(:active)])
assert_includes(coll_uuids, collections(:docker_image).uuid)
end
- test 'expires_at cannot be set too far in the past' do
+ test "move to trash in SweepTrashedCollections" do
+ c = collections(:trashed_on_next_sweep)
+ refute_empty Collection.where('uuid=? and is_trashed=false', c.uuid)
+ assert_raises(ActiveRecord::RecordNotUnique) do
+ act_as_user users(:active) do
+ Collection.create!(owner_uuid: c.owner_uuid,
+ name: c.name)
+ end
+ end
+ SweepTrashedCollections.sweep_now
+ c = Collection.unscoped.where('uuid=? and is_trashed=true', c.uuid).first
+ assert c
act_as_user users(:active) do
- t0 = db_current_time
- c = Collection.create!(manifest_text: '', name: 'foo')
- c.update_attributes! expires_at: (t0 - 2.weeks)
- c.reload
- assert_operator c.expires_at, :>, t0
+ assert Collection.create!(owner_uuid: c.owner_uuid,
+ name: c.name)
end
end
+
+ test "delete in SweepTrashedCollections" do
+ uuid = 'zzzzz-4zz18-3u1p5umicfpqszp' # deleted_on_next_sweep
+ assert_not_empty Collection.unscoped.where(uuid: uuid)
+ SweepTrashedCollections.sweep_now
+ assert_empty Collection.unscoped.where(uuid: uuid)
+ end
end
test 'find_commit_range does not bypass permissions' do
authorize_with :inactive
assert_raises ArgumentError do
- c = Commit.find_commit_range 'foo', nil, 'master', []
+ Commit.find_commit_range 'foo', nil, 'master', []
end
end
authorize_with :active
gitint = "git --git-dir #{Rails.configuration.git_internal_dir}"
IO.read("|#{gitint} tag -d testtag 2>/dev/null") # "no such tag", fine
- assert_match /^fatal: /, IO.read("|#{gitint} show testtag 2>&1")
+ assert_match(/^fatal: /, IO.read("|#{gitint} show testtag 2>&1"))
refute $?.success?
Commit.tag_in_internal_repository 'active/foo', '31ce37fe365b3dc204300a3e4c396ad333ed0556', 'testtag'
- assert_match /^commit 31ce37f/, IO.read("|#{gitint} show testtag")
+ assert_match(/^commit 31ce37f/, IO.read("|#{gitint} show testtag"))
assert $?.success?
end
Dir.mktmpdir do |touchdir|
# invalid input to maximum
a = Commit.find_commit_range('active/foo', nil, "31ce37fe365b3dc204300a3e4c396ad333ed0556 ; touch #{touchdir}/uh_oh", nil)
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
assert_equal [], a
# invalid input to maximum
a = Commit.find_commit_range('active/foo', nil, "$(uname>#{touchdir}/uh_oh)", nil)
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
assert_equal [], a
# invalid input to minimum
a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556 ; touch #{touchdir}/uh_oh", "31ce37fe365b3dc204300a3e4c396ad333ed0556", nil)
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
assert_equal [], a
# invalid input to minimum
a = Commit.find_commit_range('active/foo', "$(uname>#{touchdir}/uh_oh)", "31ce37fe365b3dc204300a3e4c396ad333ed0556", nil)
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
assert_equal [], a
# invalid input to 'excludes'
# complains "fatal: bad object 077ba2ad3ea24a929091a9e6ce545c93199b8e57"
a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556", "077ba2ad3ea24a929091a9e6ce545c93199b8e57", ["4fe459abe02d9b365932b8f5dc419439ab4e2577 ; touch #{touchdir}/uh_oh"])
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
assert_equal [], a
# invalid input to 'excludes'
# complains "fatal: bad object 077ba2ad3ea24a929091a9e6ce545c93199b8e57"
a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556", "077ba2ad3ea24a929091a9e6ce545c93199b8e57", ["$(uname>#{touchdir}/uh_oh)"])
- assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
+ assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
assert_equal [], a
end
end
cr.reload
assert_equal "Committed", cr.state
+ output_pdh = '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'
+ log_pdh = 'fa7aeb5140e2848d39b416daeef4ffc5+45'
act_as_system_user do
c.update_attributes!(state: Container::Complete,
- output: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45',
- log: 'fa7aeb5140e2848d39b416daeef4ffc5+45')
+ output: output_pdh,
+ log: log_pdh)
end
cr.reload
owner_uuid: project.uuid).count,
"Container #{out_type} should be copied to #{project.uuid}")
end
+ assert_not_nil cr.output_uuid
+ assert_not_nil cr.log_uuid
+ output = Collection.find_by_uuid cr.output_uuid
+ assert_equal output_pdh, output.portable_data_hash
+ log = Collection.find_by_uuid cr.log_uuid
+ assert_equal log_pdh, log.portable_data_hash
end
test "Container makes container request, then is cancelled" do
test "Retry on container cancelled" do
set_user_from_auth :active
cr = create_minimal_req!(priority: 1, state: "Committed", container_count_max: 2)
+ cr2 = create_minimal_req!(priority: 1, state: "Committed", container_count_max: 2, command: ["echo", "baz"])
prev_container_uuid = cr.container_uuid
c = act_as_system_user do
end
cr.reload
+ cr2.reload
assert_equal "Committed", cr.state
assert_equal prev_container_uuid, cr.container_uuid
+ assert_not_equal cr2.container_uuid, cr.container_uuid
prev_container_uuid = cr.container_uuid
act_as_system_user do
end
cr.reload
+ cr2.reload
assert_equal "Committed", cr.state
assert_not_equal prev_container_uuid, cr.container_uuid
+ assert_not_equal cr2.container_uuid, cr.container_uuid
prev_container_uuid = cr.container_uuid
c = act_as_system_user do
end
cr.reload
+ cr2.reload
assert_equal "Final", cr.state
assert_equal prev_container_uuid, cr.container_uuid
+ assert_not_equal cr2.container_uuid, cr.container_uuid
+ end
+
+ test "Output collection name setting using output_name with name collision resolution" do
+ set_user_from_auth :active
+ output_name = collections(:foo_file).name
+
+ cr = create_minimal_req!(priority: 1,
+ state: ContainerRequest::Committed,
+ output_name: output_name)
+ act_as_system_user do
+ c = Container.find_by_uuid(cr.container_uuid)
+ c.update_attributes!(state: Container::Locked)
+ c.update_attributes!(state: Container::Running)
+ c.update_attributes!(state: Container::Complete,
+ exit_code: 0,
+ output: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45',
+ log: 'fa7aeb5140e2848d39b416daeef4ffc5+45')
+ end
+ cr.save
+ assert_equal ContainerRequest::Final, cr.state
+ output_coll = Collection.find_by_uuid(cr.output_uuid)
+ # Make sure the resulting output collection name include the original name
+ # plus the date
+ assert_not_equal output_name, output_coll.name,
+ "It shouldn't exist more than one collection with the same owner and name '${output_name}'"
+ assert output_coll.name.include?(output_name),
+ "New name should include original name"
+ assert_match /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/, output_coll.name,
+ "New name should include ISO8601 date"
end
test "Finalize committed request when reusing a finished container" do
end
end
end
+
+ [
+ [{"partitions" => ["fastcpu","vfastcpu", 100]}, ContainerRequest::Committed, ActiveRecord::RecordInvalid],
+ [{"partitions" => ["fastcpu","vfastcpu", 100]}, ContainerRequest::Uncommitted],
+ [{"partitions" => "fastcpu"}, ContainerRequest::Committed, ActiveRecord::RecordInvalid],
+ [{"partitions" => "fastcpu"}, ContainerRequest::Uncommitted],
+ [{"partitions" => ["fastcpu","vfastcpu"]}, ContainerRequest::Committed],
+ ].each do |sp, state, expected|
+ test "create container request with scheduling_parameters #{sp} in state #{state} and verify #{expected}" do
+ common_attrs = {cwd: "test",
+ priority: 1,
+ command: ["echo", "hello"],
+ output_path: "test",
+ scheduling_parameters: sp,
+ mounts: {"test" => {"kind" => "json"}}}
+ set_user_from_auth :active
+
+ if expected == ActiveRecord::RecordInvalid
+ assert_raises(ActiveRecord::RecordInvalid) do
+ create_minimal_req!(common_attrs.merge({state: state}))
+ end
+ else
+ cr = create_minimal_req!(common_attrs.merge({state: state}))
+ assert_equal sp, cr.scheduling_parameters
+
+ if state == ContainerRequest::Committed
+ c = Container.find_by_uuid(cr.container_uuid)
+ assert_equal sp, c.scheduling_parameters
+ end
+ end
+ end
+ end
end
test "find_reusable method should select higher priority queued container" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment:{"var" => "queued"}})
- c_low_priority, _ = minimal_new(common_attrs.merge({priority:1}))
- c_high_priority, _ = minimal_new(common_attrs.merge({priority:2}))
+ c_low_priority, _ = minimal_new(common_attrs.merge({use_existing:false, priority:1}))
+ c_high_priority, _ = minimal_new(common_attrs.merge({use_existing:false, priority:2}))
+ assert_not_equal c_low_priority.uuid, c_high_priority.uuid
assert_equal Container::Queued, c_low_priority.state
assert_equal Container::Queued, c_high_priority.state
reused = Container.find_reusable(common_attrs)
output: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'
}
- c_older, _ = minimal_new(common_attrs)
- c_recent, _ = minimal_new(common_attrs)
+ c_older, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_recent, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ assert_not_equal c_older.uuid, c_recent.uuid
set_user_from_auth :dispatch1
c_older.update_attributes!({state: Container::Locked})
c_output1 = Container.create common_attrs
c_output2 = Container.create common_attrs
+ assert_not_equal c_output1.uuid, c_output2.uuid
cr = ContainerRequest.new common_attrs
cr.state = ContainerRequest::Committed
test "find_reusable method should select running container by start date" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "running"}})
- c_slower, _ = minimal_new(common_attrs)
- c_faster_started_first, _ = minimal_new(common_attrs)
- c_faster_started_second, _ = minimal_new(common_attrs)
+ c_slower, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_faster_started_first, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_faster_started_second, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ # Confirm the 3 container UUIDs are different.
+ assert_equal 3, [c_slower.uuid, c_faster_started_first.uuid, c_faster_started_second.uuid].uniq.length
set_user_from_auth :dispatch1
c_slower.update_attributes!({state: Container::Locked})
c_slower.update_attributes!({state: Container::Running,
test "find_reusable method should select running container by progress" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "running2"}})
- c_slower, _ = minimal_new(common_attrs)
- c_faster_started_first, _ = minimal_new(common_attrs)
- c_faster_started_second, _ = minimal_new(common_attrs)
+ c_slower, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_faster_started_first, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_faster_started_second, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ # Confirm the 3 container UUIDs are different.
+ assert_equal 3, [c_slower.uuid, c_faster_started_first.uuid, c_faster_started_second.uuid].uniq.length
set_user_from_auth :dispatch1
c_slower.update_attributes!({state: Container::Locked})
c_slower.update_attributes!({state: Container::Running,
test "find_reusable method should select locked container most likely to start sooner" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "locked"}})
- c_low_priority, _ = minimal_new(common_attrs)
- c_high_priority_older, _ = minimal_new(common_attrs)
- c_high_priority_newer, _ = minimal_new(common_attrs)
+ c_low_priority, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_high_priority_older, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_high_priority_newer, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ # Confirm the 3 container UUIDs are different.
+ assert_equal 3, [c_low_priority.uuid, c_high_priority_older.uuid, c_high_priority_newer.uuid].uniq.length
set_user_from_auth :dispatch1
c_low_priority.update_attributes!({state: Container::Locked,
priority: 1})
test "find_reusable method should select running over failed container" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "failed_vs_running"}})
- c_failed, _ = minimal_new(common_attrs)
- c_running, _ = minimal_new(common_attrs)
+ c_failed, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_running, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ assert_not_equal c_failed.uuid, c_running.uuid
set_user_from_auth :dispatch1
c_failed.update_attributes!({state: Container::Locked})
c_failed.update_attributes!({state: Container::Running})
test "find_reusable method should select complete over running container" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "completed_vs_running"}})
- c_completed, _ = minimal_new(common_attrs)
- c_running, _ = minimal_new(common_attrs)
+ c_completed, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_running, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ assert_not_equal c_completed.uuid, c_running.uuid
set_user_from_auth :dispatch1
c_completed.update_attributes!({state: Container::Locked})
c_completed.update_attributes!({state: Container::Running})
test "find_reusable method should select running over locked container" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "running_vs_locked"}})
- c_locked, _ = minimal_new(common_attrs)
- c_running, _ = minimal_new(common_attrs)
+ c_locked, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_running, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ assert_not_equal c_running.uuid, c_locked.uuid
set_user_from_auth :dispatch1
c_locked.update_attributes!({state: Container::Locked})
c_running.update_attributes!({state: Container::Locked})
test "find_reusable method should select locked over queued container" do
set_user_from_auth :active
common_attrs = REUSABLE_COMMON_ATTRS.merge({environment: {"var" => "running_vs_locked"}})
- c_locked, _ = minimal_new(common_attrs)
- c_queued, _ = minimal_new(common_attrs)
+ c_locked, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ c_queued, _ = minimal_new(common_attrs.merge({use_existing: false}))
+ assert_not_equal c_queued.uuid, c_locked.uuid
set_user_from_auth :dispatch1
c_locked.update_attributes!({state: Container::Locked})
reused = Container.find_reusable(common_attrs)
create_superuser_token active_user_token
end
assert_not_nil e
- assert_equal "Token already exists but is not a superuser token.", e.message
+ assert_equal "Token exists but is not a superuser token.", e.message
+ end
+
+ test "specified token has limited scope" do
+ active_user_token = api_client_authorizations("data_manager").api_token
+ e = assert_raises RuntimeError do
+ create_superuser_token active_user_token
+ end
+ assert_not_nil e
+ assert_match /^Token exists but has limited scope/, e.message
+ end
+
+ test "existing token has limited scope" do
+ active_user_token = api_client_authorizations("admin_vm").api_token
+ ApiClientAuthorization.
+ where(user_id: system_user.id).
+ update_all(scopes: ["GET /"])
+ fixture_tokens = ApiClientAuthorization.all.collect(&:api_token)
+ new_token = create_superuser_token
+ refute_includes(fixture_tokens, new_token)
end
end
test 'command line help' do
cmd = Rails.root.join('script/fail-jobs.rb').to_s
- assert_match /Options:.*--before=/m, File.popen([cmd, '--help']).read
+ assert_match(/Options:.*--before=/m, File.popen([cmd, '--help']).read)
end
protected
def assert_end_states
- @job.values.map &:reload
+ @job.values.map(&:reload)
assert_equal 'Failed', @job[:before_reboot].state
assert_equal false, @job[:before_reboot].running
assert_equal false, @job[:before_reboot].success
# Ensure valid_attrs doesn't produce errors -- otherwise we will
# not know whether errors reported below are actually caused by
# invalid_attrs.
- dummy = Job.create! job_attrs
+ Job.create! job_attrs
job = Job.create job_attrs(invalid_attrs)
assert_raises(ActiveRecord::RecordInvalid, ArgumentError,
parameters.each do |parameter|
expectations = parameter[2]
- if parameter[1] == 'use_current_user_uuid'
+ if 'use_current_user_uuid' == parameter[1]
parameter[1] = Thread.current[:user].uuid
end
assert_equal "Failed", job.state
end
+ test "admin user can cancel a running job despite lock" do
+ set_user_from_auth :active_trustedclient
+ job = Job.create! job_attrs
+ job.lock current_user.uuid
+ assert_equal Job::Running, job.state
+
+ set_user_from_auth :spectator
+ assert_raises do
+ job.update_attributes!(state: Job::Cancelled)
+ end
+
+ set_user_from_auth :admin
+ job.reload
+ assert_equal Job::Running, job.state
+ job.update_attributes!(state: Job::Cancelled)
+ assert_equal Job::Cancelled, job.state
+ end
+
test "verify job queue position" do
job1 = Job.create! job_attrs
assert_equal 'Queued', job1.state, "Incorrect job state for newly created job1"
}
assert_raises(ActiveRecord::RecordInvalid,
"created job with a collection uuid in script_parameters") do
- job = Job.create!(job_attrs(bad_params))
+ Job.create!(job_attrs(bad_params))
end
end
# appear too, but only if they are _not_ listed in known_logs
# (i.e., we do not make any assertions about logs not mentioned in
# either "known" or "expected".)
- result_ids = result.collect &:id
+ result_ids = result.collect(&:id)
expected_logs.each do |want|
assert_includes result_ids, logs(want).id
end
conffile = Rails.root.join 'tmp', 'compute65535.conf'
File.unlink conffile rescue nil
assert Node.dns_server_update 'compute65535', '127.0.0.1'
- assert_match /\"1\.0\.0\.127\.in-addr\.arpa\. IN PTR compute65535\.zzzzz\.arvadosapi\.com\"/, IO.read(conffile)
+ assert_match(/\"1\.0\.0\.127\.in-addr\.arpa\. IN PTR compute65535\.zzzzz\.arvadosapi\.com\"/, IO.read(conffile))
File.unlink conffile
end
test "create object with non-existent #{o_class} owner" do
assert_raises(ActiveRecord::RecordInvalid,
"create should fail with random owner_uuid") do
- i = Specimen.create!(owner_uuid: o_class.generate_uuid)
+ Specimen.create!(owner_uuid: o_class.generate_uuid)
end
i = Specimen.create(owner_uuid: o_class.generate_uuid)
o = eval ofixt
assert_equal(true, Specimen.where(owner_uuid: o.uuid).any?,
"need something to be owned by #{o.uuid} for this test")
- old_uuid = o.uuid
new_uuid = o.uuid.sub(/..........$/, rand(2**256).to_s(36)[0..9])
assert(!o.update_attributes(uuid: new_uuid),
"should not change uuid of #{ofixt} that owns objects")
sp_grp = Group.create!
sp = Specimen.create!(owner_uuid: sp_grp.uuid)
- manage_perm = Link.create!(link_class: 'permission',
- name: 'can_manage',
- tail_uuid: owner_grp.uuid,
- head_uuid: sp_grp.uuid)
+ Link.create!(link_class: 'permission',
+ name: 'can_manage',
+ tail_uuid: owner_grp.uuid,
+ head_uuid: sp_grp.uuid)
# active user owns owner_grp, which has can_manage permission on sp_grp
# user should be able to add permissions on sp.
head_uuid: sp.uuid,
link_class: 'permission',
name: 'can_write')
- test_uuid = test_perm.uuid
assert test_perm.save, "could not save new permission on target object"
assert test_perm.destroy, "could not delete new permission on target object"
end
- # TODO(twp): fix bug #3091, which should fix this test.
- test "can_manage permission on a non-group object" do
- skip
+ # bug #3091
+ skip "can_manage permission on a non-group object" do
set_user_from_auth :admin
ob = Specimen.create!
pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
assert_equal PipelineInstance::New, pi.state, 'expected state to be New after adding component with input'
assert_equal pi.components.size, 1, 'expected one component'
+ assert_nil pi.started_at, 'expected started_at to be nil on new pipeline instance'
+ assert_nil pi.finished_at, 'expected finished_at to be nil on new pipeline instance'
# add a component with no input not required
component = {'script_parameters' => {"input_not_provided" => {"required" => false}}}
pi.save
pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
assert_equal PipelineInstance::RunningOnServer, pi.state, 'expected state to be RunningOnServer after updating state to RunningOnServer'
+ assert_not_nil pi.started_at, 'expected started_at to have a value on a running pipeline instance'
+ assert_nil pi.finished_at, 'expected finished_at to be nil on a running pipeline instance'
pi.state = PipelineInstance::Paused
pi.save
pi.save
pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
assert_equal PipelineInstance::Complete, pi.state, 'expected state to be Complete after updating state to Complete'
+ assert_not_nil pi.started_at, 'expected started_at to have a value on a completed pipeline instance'
+ assert_not_nil pi.finished_at, 'expected finished_at to have a value on a completed pipeline instance'
pi.state = 'bogus'
pi.save
pi.save
pi = PipelineInstance.find_by_uuid 'zzzzz-d1hrv-f4gneyn6br1xize'
assert_equal PipelineInstance::Failed, pi.state, 'expected state to be Failed after updating state to Failed'
+ assert_not_nil pi.started_at, 'expected started_at to have a value on a failed pipeline instance'
+ assert_not_nil pi.finished_at, 'expected finished_at to have a value on a failed pipeline instance'
end
test "update attributes for pipeline with two components" do
component2 = {'script_parameters' => {"something_else" => "xxxad4b39ca5a924e481008009d94e32+210", "input_missing" => {"required" => true}}}
pi.components['first'] = component1
pi.components['second'] = component2
- components = pi.components
Thread.current[:user] = users(:admin)
pi.update_attribute 'components', pi.components
updated_name = updated_src_collection.name
assert_equal true, updated_name.include?(src_collection.name)
- match = updated_name.match /^test collection.*salvaged data at (.*)\)$/
+ match = updated_name.match(/^test collection.*salvaged data at (.*)\)$/)
assert_not_nil match
assert_not_nil match[1]
assert_empty updated_src_collection.manifest_text
# match[1] is the uuid of the new collection created from src_collection's salvaged data
# use this to get the new collection and verify
new_collection = Collection.find_by_uuid match[1]
- match = new_collection.name.match /^salvaged from (.*),.*/
+ match = new_collection.name.match(/^salvaged from (.*),.*/)
assert_not_nil match
assert_equal src_collection.uuid, match[1]
end
test "salvage collection with no uuid required argument" do
- e = assert_raises RuntimeError do
+ assert_raises RuntimeError do
salvage_collection nil
end
end
e = assert_raises RuntimeError do
salvage_collection collections('user_agreement').uuid
end
- assert_match /Error during arv-put: pid \d+ exit \d+ \(cmd was \"arv-put .*\"\)/, e.message
+ assert_match(/Error during arv-put: pid \d+ exit \d+ \(cmd was \"arv-put .*\"\)/, e.message)
end
# This test uses BAD_MANIFEST, which has the following flaws:
updated_name = updated_src_collection.name
assert_equal true, updated_name.include?(src_collection.name)
- match = updated_name.match /^test collection.*salvaged data at (.*)\)$/
+ match = updated_name.match(/^test collection.*salvaged data at (.*)\)$/)
assert_not_nil match
assert_not_nil match[1]
assert_empty updated_src_collection.manifest_text
# match[1] is the uuid of the new collection created from src_collection's salvaged data
# use this to get the new collection and verify
new_collection = Collection.find_by_uuid match[1]
- match = new_collection.name.match /^salvaged from (.*),.*/
+ match = new_collection.name.match(/^salvaged from (.*),.*/)
assert_not_nil match
assert_equal src_collection.uuid, match[1]
# verify the new collection's manifest includes the bad locators
test "admin can't clear username when user owns repositories" do
set_user_from_auth :admin
user = users(:active)
- start_username = user.username
user.username = nil
assert_not_allowed { user.save }
refute_empty(user.errors[:username])
assert @uninvited_user.can? :write=>"#{@uninvited_user.uuid}"
assert @uninvited_user.can? :manage=>"#{@uninvited_user.uuid}"
- assert @uninvited_user.groups_i_can(:read).size == 1, "inactive and uninvited user can only read anonymous user group"
- assert @uninvited_user.groups_i_can(:read).first.ends_with? 'anonymouspublic' , "inactive and uninvited user can only read anonymous user group"
- assert @uninvited_user.groups_i_can(:write).size == 0, "inactive and uninvited user should not be able write to any groups"
- assert @uninvited_user.groups_i_can(:manage).size == 0, "inactive and uninvited user should not be able manage any groups"
+ assert_equal(@uninvited_user.groups_i_can(:read).sort,
+ [@uninvited_user.uuid, groups(:anonymous_group).uuid].sort)
+ assert_equal(@uninvited_user.groups_i_can(:write),
+ [@uninvited_user.uuid])
+ assert_equal(@uninvited_user.groups_i_can(:manage),
+ [@uninvited_user.uuid])
end
test "find user method checks" do
+++ /dev/null
-require 'bundler'
-require 'socket'
-
-$ARV_API_SERVER_DIR = File.expand_path('../..', __FILE__)
-
-s = TCPServer.new('0.0.0.0', 0)
-WEBSOCKET_PORT = s.addr[1]
-s.close
-SERVER_PID_PATH = "tmp/pids/passenger.#{WEBSOCKET_PORT}.pid"
-
-class WebsocketTestRunner < MiniTest::Unit
- def _system(*cmd)
- Bundler.with_clean_env do
- if not system({'ARVADOS_WEBSOCKETS' => 'ws-only', 'RAILS_ENV' => 'test'}, *cmd)
- raise RuntimeError, "Command failed with exit status #{$?}: #{cmd.inspect}"
- end
- end
- end
-
- def _run(args=[])
- server_pid = Dir.chdir($ARV_API_SERVER_DIR) do |apidir|
- # Only passenger seems to be able to run the websockets server successfully.
- _system('passenger', 'start', '-d', "-p#{WEBSOCKET_PORT}")
- timeout = Time.now.tv_sec + 10
- begin
- sleep 0.2
- begin
- server_pid = IO.read(SERVER_PID_PATH).to_i
- good_pid = (server_pid > 0) and (Process.kill(0, pid) rescue false)
- rescue Errno::ENOENT
- good_pid = false
- end
- end while (not good_pid) and (Time.now.tv_sec < timeout)
- if not good_pid
- raise RuntimeError, "could not find API server Rails pid"
- end
- server_pid
- end
- begin
- super(args)
- ensure
- Dir.chdir($ARV_API_SERVER_DIR) do
- _system('passenger', 'stop', "-p#{WEBSOCKET_PORT}")
- end
- # DatabaseCleaner leaves the database empty. Prefer to leave it full.
- dc = DatabaseController.new
- dc.define_singleton_method :render do |*args| end
- dc.reset
- end
- end
-end
-
-MiniTest::Unit.runner = WebsocketTestRunner.new
if err := srv.Start(); err != nil {
log.Fatal(err)
}
- if _, err := daemon.SdNotify("READY=1"); err != nil {
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
log.Printf("Error notifying init daemon: %v", err)
}
log.Println("Listening at", srv.Addr)
et = 'add'
else:
et = 'remove'
- if ev['properties']['new_attributes']['expires_at'] is not None:
+ if ev['properties']['new_attributes']['trash_at'] is not None:
et = 'remove'
self.evqueue.put((self.project, et, ev['object_uuid']))
PollInterval: time.Duration(theConfig.PollPeriod),
DoneProcessing: make(chan struct{})}
- if _, err := daemon.SdNotify("READY=1"); err != nil {
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
log.Printf("Error notifying init daemon: %v", err)
}
sbatchArgs = append(sbatchArgs, fmt.Sprintf("--job-name=%s", container.UUID))
sbatchArgs = append(sbatchArgs, fmt.Sprintf("--mem-per-cpu=%d", int(memPerCPU)))
sbatchArgs = append(sbatchArgs, fmt.Sprintf("--cpus-per-task=%d", container.RuntimeConstraints.VCPUs))
- if container.RuntimeConstraints.Partition != nil {
- sbatchArgs = append(sbatchArgs, fmt.Sprintf("--partition=%s", strings.Join(container.RuntimeConstraints.Partition, ",")))
+ if container.SchedulingParameters.Partitions != nil {
+ sbatchArgs = append(sbatchArgs, fmt.Sprintf("--partition=%s", strings.Join(container.SchedulingParameters.Partitions, ",")))
}
return exec.Command("sbatch", sbatchArgs...)
b, _ := ioutil.ReadAll(stdoutReader)
stdoutReader.Close()
stdoutChan <- b
+ close(stdoutChan)
}()
stderrChan := make(chan []byte)
b, _ := ioutil.ReadAll(stderrReader)
stderrReader.Close()
stderrChan <- b
+ close(stderrChan)
}()
// Send a tiny script on stdin to execute the crunch-run command
io.WriteString(stdinWriter, execScript(append(crunchRunCommand, container.UUID)))
stdinWriter.Close()
- err = cmd.Wait()
-
stdoutMsg := <-stdoutChan
stderrmsg := <-stderrChan
- close(stdoutChan)
- close(stderrChan)
+ err = cmd.Wait()
if err != nil {
submitErr = fmt.Errorf("Container submission failed: %v: %v (stderr: %q)", cmd.Args, err, stderrmsg)
// Mutex between squeue sync and running sbatch or scancel.
squeueUpdater.SlurmLock.Lock()
- err := scancelCmd(container).Run()
+ cmd := scancelCmd(container)
+ msg, err := cmd.CombinedOutput()
squeueUpdater.SlurmLock.Unlock()
if err != nil {
- log.Printf("Error stopping container %s with scancel: %v",
- container.UUID, err)
+ log.Printf("Error stopping container %s with %v %v: %v %v",
+ container.UUID, cmd.Path, cmd.Args, err, string(msg))
if squeueUpdater.CheckSqueue(container.UUID) {
log.Printf("Container %s is still in squeue after scancel.",
container.UUID)
return exec.Command("echo")
}
- container := s.integrationTest(c, func() *exec.Cmd { return exec.Command("echo", "zzzzz-dz642-queuedcontainer") },
+ container := s.integrationTest(c,
+ func() *exec.Cmd { return exec.Command("echo", "zzzzz-dz642-queuedcontainer") },
[]string(nil),
func(dispatcher *dispatch.Dispatcher, container arvados.Container) {
dispatcher.UpdateState(container.UUID, dispatch.Running)
}(squeueCmd)
squeueCmd = newSqueueCmd
- // There should be no queued containers now
+ // There should be one queued container
params := arvadosclient.Dict{
"filters": [][]string{{"state", "=", "Queued"}},
}
func (s *MockArvadosServerSuite) TestSbatchPartition(c *C) {
theConfig.SbatchArguments = nil
- container := arvados.Container{UUID: "123", RuntimeConstraints: arvados.RuntimeConstraints{RAM: 250000000, VCPUs: 1, Partition: []string{"blurb", "b2"}}}
+ container := arvados.Container{UUID: "123", RuntimeConstraints: arvados.RuntimeConstraints{RAM: 250000000, VCPUs: 1}, SchedulingParameters: arvados.SchedulingParameters{Partitions: []string{"blurb", "b2"}}}
sbatchCmd := sbatchFunc(container)
var expected []string
import (
"bufio"
+ "io"
+ "io/ioutil"
"log"
"os/exec"
"sync"
log.Printf("Error creating stdout pipe for squeue: %v", err)
return
}
+
+ stderrReader, err := cmd.StderrPipe()
+ if err != nil {
+ log.Printf("Error creating stderr pipe for squeue: %v", err)
+ return
+ }
+
err = cmd.Start()
if err != nil {
log.Printf("Error running squeue: %v", err)
return
}
+
+ stderrChan := make(chan []byte)
+ go func() {
+ b, _ := ioutil.ReadAll(stderrReader)
+ stderrChan <- b
+ close(stderrChan)
+ }()
+
scanner := bufio.NewScanner(sq)
for scanner.Scan() {
newSqueueContents = append(newSqueueContents, scanner.Text())
}
- if err := scanner.Err(); err != nil {
- cmd.Wait()
- log.Printf("Error reading from squeue pipe: %v", err)
- return
- }
+ io.Copy(ioutil.Discard, sq)
+
+ stderrmsg := <-stderrChan
err = cmd.Wait()
+
+ if scanner.Err() != nil {
+ log.Printf("Error reading from squeue pipe: %v", err)
+ }
if err != nil {
- log.Printf("Error running squeue: %v", err)
- return
+ log.Printf("Error running %v %v: %v %q", cmd.Path, cmd.Args, err, string(stderrmsg))
}
- squeue.squeueCond.L.Lock()
- squeue.squeueContents = newSqueueContents
- squeue.squeueCond.Broadcast()
- squeue.squeueCond.L.Unlock()
+ if scanner.Err() == nil && err == nil {
+ squeue.squeueCond.L.Lock()
+ squeue.squeueContents = newSqueueContents
+ squeue.squeueCond.Broadcast()
+ squeue.squeueCond.L.Unlock()
+ }
}
// CheckSqueue checks if a given container UUID is in the slurm queue. This
collectionPaths := []string{}
runner.Binds = nil
+ needCertMount := true
for bind, mnt := range runner.Container.Mounts {
if bind == "stdout" {
return fmt.Errorf("Stdout path does not start with OutputPath: %s, %s", mnt.Path, prefix)
}
}
+ if bind == "/etc/arvados/ca-certificates.crt" {
+ needCertMount = false
+ }
switch {
case mnt.Kind == "collection":
return fmt.Errorf("Output path does not correspond to a writable mount point")
}
+ if wantAPI := runner.Container.RuntimeConstraints.API; needCertMount && wantAPI != nil && *wantAPI {
+ for _, certfile := range arvadosclient.CertFiles {
+ _, err := os.Stat(certfile)
+ if err == nil {
+ runner.Binds = append(runner.Binds, fmt.Sprintf("%s:/etc/arvados/ca-certificates.crt:ro", certfile))
+ break
+ }
+ }
+ }
+
if pdhOnly {
arvMountCmd = append(arvMountCmd, "--mount-by-pdh", "by_id")
} else {
err = runner.ArvClient.Create("collections",
arvadosclient.Dict{
"collection": arvadosclient.Dict{
- "expires_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
+ "trash_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
"name": "output for " + runner.Container.UUID,
"manifest_text": manifestText}},
&response)
err = runner.ArvClient.Create("collections",
arvadosclient.Dict{
"collection": arvadosclient.Dict{
- "expires_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
+ "trash_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
"name": "logs for " + runner.Container.UUID,
"manifest_text": mt}},
&response)
func (runner *ContainerRunner) UpdateContainerFinal() error {
update := arvadosclient.Dict{}
update["state"] = runner.finalState
+ if runner.LogsPDH != nil {
+ update["log"] = *runner.LogsPDH
+ }
if runner.finalState == "Complete" {
- if runner.LogsPDH != nil {
- update["log"] = *runner.LogsPDH
- }
if runner.ExitCode != nil {
update["exit_code"] = *runner.ExitCode
}
checkErr(err)
if runner.finalState == "Queued" {
+ runner.CrunchLog.Close()
runner.UpdateContainerFinal()
return
}
// check for and/or load image
err = runner.LoadImage()
if err != nil {
+ runner.finalState = "Cancelled"
err = fmt.Errorf("While loading container image: %v", err)
return
}
// set up FUSE mount and binds
err = runner.SetupMounts()
if err != nil {
+ runner.finalState = "Cancelled"
err = fmt.Errorf("While setting up mounts: %v", err)
return
}
cgroupRoot := flag.String("cgroup-root", "/sys/fs/cgroup", "path to sysfs cgroup tree")
cgroupParent := flag.String("cgroup-parent", "docker", "name of container's parent cgroup (ignored if -cgroup-parent-subsystem is used)")
cgroupParentSubsystem := flag.String("cgroup-parent-subsystem", "", "use current cgroup for given subsystem as parent cgroup for container")
+ caCertsPath := flag.String("ca-certs", "", "Path to TLS root certificates")
flag.Parse()
containerId := flag.Arg(0)
+ if *caCertsPath != "" {
+ arvadosclient.CertFiles = []string{*caCertsPath}
+ }
+
api, err := arvadosclient.MakeArvadosClient()
if err != nil {
log.Fatalf("%s: %v", containerId, err)
return nil, nil
}
+func stubCert(temp string) string {
+ path := temp + "/ca-certificates.crt"
+ crt, _ := os.Create(path)
+ crt.Close()
+ arvadosclient.CertFiles = []string{path}
+ return path
+}
+
func (s *TestSuite) TestSetupMounts(c *C) {
api := &ArvTestClient{}
kc := &KeepTestClient{}
am := &ArvMountCmdLine{}
cr.RunArvMount = am.ArvMountTest
- realTemp, err := ioutil.TempDir("", "crunchrun_test-")
+ realTemp, err := ioutil.TempDir("", "crunchrun_test1-")
+ c.Assert(err, IsNil)
+ certTemp, err := ioutil.TempDir("", "crunchrun_test2-")
c.Assert(err, IsNil)
+ stubCertPath := stubCert(certTemp)
+
defer os.RemoveAll(realTemp)
+ defer os.RemoveAll(certTemp)
i := 0
cr.MkTempDir = func(_ string, prefix string) (string, error) {
checkEmpty()
}
+ {
+ i = 0
+ cr.Container.Mounts = make(map[string]arvados.Mount)
+ cr.Container.Mounts["/tmp"] = arvados.Mount{Kind: "tmp"}
+ cr.OutputPath = "/tmp"
+
+ apiflag := true
+ cr.Container.RuntimeConstraints.API = &apiflag
+
+ err := cr.SetupMounts()
+ c.Check(err, IsNil)
+ c.Check(am.Cmd, DeepEquals, []string{"--foreground", "--allow-other", "--read-write", "--mount-by-pdh", "by_id", realTemp + "/keep1"})
+ c.Check(cr.Binds, DeepEquals, []string{realTemp + "/2:/tmp", stubCertPath + ":/etc/arvados/ca-certificates.crt:ro"})
+ cr.CleanupDirs()
+ checkEmpty()
+
+ apiflag = false
+ }
+
{
i = 0
cr.Container.Mounts = map[string]arvados.Mount{
const MaxLogLine = 1 << 14 // Child stderr lines >16KiB will be split
+var (
+ signalOnDeadPPID int = 15
+ ppidCheckInterval = time.Second
+)
+
func main() {
reporter := crunchstat.Reporter{
Logger: log.New(os.Stderr, "crunchstat: ", 0),
flag.StringVar(&reporter.CgroupRoot, "cgroup-root", "", "Root of cgroup tree")
flag.StringVar(&reporter.CgroupParent, "cgroup-parent", "", "Name of container parent under cgroup")
flag.StringVar(&reporter.CIDFile, "cgroup-cid", "", "Path to container id file")
+ flag.IntVar(&signalOnDeadPPID, "signal-on-dead-ppid", signalOnDeadPPID, "Signal to send child if crunchstat's parent process disappears (0 to disable)")
+ flag.DurationVar(&ppidCheckInterval, "ppid-check-interval", ppidCheckInterval, "Time between checks for parent process disappearance")
pollMsec := flag.Int64("poll", 1000, "Reporting interval, in milliseconds")
flag.Parse()
if reporter.CgroupRoot == "" {
reporter.Logger.Fatal("error: must provide -cgroup-root")
+ } else if signalOnDeadPPID < 0 {
+ reporter.Logger.Fatalf("-signal-on-dead-ppid=%d is invalid (use a positive signal number, or 0 to disable)", signalOnDeadPPID)
}
reporter.PollPeriod = time.Duration(*pollMsec) * time.Millisecond
signal.Notify(sigChan, syscall.SIGTERM)
signal.Notify(sigChan, syscall.SIGINT)
+ // Kill our child proc if our parent process disappears
+ if signalOnDeadPPID != 0 {
+ go sendSignalOnDeadPPID(ppidCheckInterval, signalOnDeadPPID, os.Getppid(), cmd, logger)
+ }
+
// Funnel stderr through our channel
stderr_pipe, err := cmd.StderrPipe()
if err != nil {
return cmd.Wait()
}
+func sendSignalOnDeadPPID(intvl time.Duration, signum, ppidOrig int, cmd *exec.Cmd, logger *log.Logger) {
+ ticker := time.NewTicker(intvl)
+ for _ = range ticker.C {
+ ppid := os.Getppid()
+ if ppid == ppidOrig {
+ continue
+ }
+ if cmd.Process == nil {
+ // Child process isn't running yet
+ continue
+ }
+ logger.Printf("notice: crunchstat ppid changed from %d to %d -- killing child pid %d with signal %d", ppidOrig, ppid, cmd.Process.Pid, signum)
+ err := cmd.Process.Signal(syscall.Signal(signum))
+ if err != nil {
+ logger.Printf("error: sending signal: %s", err)
+ continue
+ }
+ ticker.Stop()
+ break
+ }
+}
+
func copyPipeToChildLog(in io.ReadCloser, logger *log.Logger) {
reader := bufio.NewReaderSize(in, MaxLogLine)
var prefix string
import (
"bufio"
"bytes"
+ "fmt"
"io"
+ "io/ioutil"
"log"
"math/rand"
+ "os"
+ "os/exec"
+ "sync"
+ "syscall"
"testing"
"time"
)
logger := log.New(w, "", 0)
return logger, bufio.NewReader(r)
}
+
+func TestSignalOnDeadPPID(t *testing.T) {
+ if !testDeadParent(t, 0) {
+ t.Fatal("child should still be alive after parent dies")
+ }
+ if testDeadParent(t, 15) {
+ t.Fatal("child should have been killed when parent died")
+ }
+}
+
+// testDeadParent returns true if crunchstat's child proc is still
+// alive after its parent dies.
+func testDeadParent(t *testing.T, signum int) bool {
+ var err error
+ var bin, childlockfile, parentlockfile *os.File
+ for _, f := range []**os.File{&bin, &childlockfile, &parentlockfile} {
+ *f, err = ioutil.TempFile("", "crunchstat_")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer (*f).Close()
+ defer os.Remove((*f).Name())
+ }
+
+ bin.Close()
+ err = exec.Command("go", "build", "-o", bin.Name()).Run()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = syscall.Flock(int(parentlockfile.Fd()), syscall.LOCK_EX)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cmd := exec.Command("bash", "-c", `
+set -e
+"$BINFILE" -cgroup-root=/none -ppid-check-interval=10ms -signal-on-dead-ppid="$SIGNUM" bash -c '
+ set -e
+ unlock() {
+ flock --unlock "$CHILDLOCKFD"
+ kill %1
+ }
+ trap unlock TERM
+ flock --exclusive "$CHILDLOCKFD"
+ echo -n "$$" > "$CHILDLOCKFILE"
+ flock --unlock "$PARENTLOCKFD"
+ sleep 20 </dev/null >/dev/null 2>/dev/null &
+ wait %1
+ unlock
+' &
+
+# wait for inner bash to start, to ensure $BINFILE has seen this bash proc as its initial PPID
+flock --exclusive "$PARENTLOCKFILE" true
+`)
+ cmd.Env = append(os.Environ(),
+ "SIGNUM="+fmt.Sprintf("%d", signum),
+ "PARENTLOCKFD=3",
+ "PARENTLOCKFILE="+parentlockfile.Name(),
+ "CHILDLOCKFD=4",
+ "CHILDLOCKFILE="+childlockfile.Name(),
+ "BINFILE="+bin.Name())
+ cmd.ExtraFiles = []*os.File{parentlockfile, childlockfile}
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cmd.Start()
+ defer cmd.Wait()
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ defer wg.Wait()
+ for _, rdr := range []io.ReadCloser{stderr, stdout} {
+ go func(rdr io.ReadCloser) {
+ defer wg.Done()
+ buf := make([]byte, 1024)
+ for {
+ n, err := rdr.Read(buf)
+ if n > 0 {
+ t.Logf("%s", buf[:n])
+ }
+ if err != nil {
+ return
+ }
+ }
+ }(rdr)
+ }
+
+ // Wait until inner bash process releases parentlockfile
+ // (which means it has locked childlockfile and written its
+ // PID)
+ err = exec.Command("flock", "--exclusive", parentlockfile.Name(), "true").Run()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ childDone := make(chan bool)
+ go func() {
+ // Notify the main thread when the inner bash process
+ // releases its lock on childlockfile (which means
+ // either its sleep process ended or it received a
+ // TERM signal).
+ t0 := time.Now()
+ err = exec.Command("flock", "--exclusive", childlockfile.Name(), "true").Run()
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("child done after %s", time.Since(t0))
+ close(childDone)
+ }()
+
+ select {
+ case <-time.After(500 * time.Millisecond):
+ // Inner bash process is still alive after the timeout
+ // period. Kill it now, so our stdout and stderr pipes
+ // can finish and we don't leave a mess of child procs
+ // behind.
+ buf, err := ioutil.ReadFile(childlockfile.Name())
+ if err != nil {
+ t.Fatal(err)
+ }
+ var childPID int
+ _, err = fmt.Sscanf(string(buf), "%d", &childPID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ child, err := os.FindProcess(childPID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ child.Signal(syscall.Signal(15))
+ return true
+
+ case <-childDone:
+ // Inner bash process ended soon after its grandparent
+ // ended.
+ return false
+ }
+}
+++ /dev/null
-// Deals with parsing Collection responses from API Server.
-
-package collection
-
-import (
- "flag"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "git.curoverse.com/arvados.git/sdk/go/manifest"
- "git.curoverse.com/arvados.git/sdk/go/util"
- "log"
- "os"
- "runtime/pprof"
- "time"
-)
-
-var (
- HeapProfileFilename string
-)
-
-// Collection representation
-type Collection struct {
- UUID string
- OwnerUUID string
- ReplicationLevel int
- BlockDigestToSize map[blockdigest.BlockDigest]int
- TotalSize int
-}
-
-// ReadCollections holds information about collections from API server
-type ReadCollections struct {
- ReadAllCollections bool
- UUIDToCollection map[string]Collection
- OwnerToCollectionSize map[string]int
- BlockToDesiredReplication map[blockdigest.DigestWithSize]int
- CollectionUUIDToIndex map[string]int
- CollectionIndexToUUID []string
- BlockToCollectionIndices map[blockdigest.DigestWithSize][]int
-}
-
-// GetCollectionsParams params
-type GetCollectionsParams struct {
- Client *arvadosclient.ArvadosClient
- Logger *logger.Logger
- BatchSize int
-}
-
-// SdkCollectionInfo holds collection info from api
-type SdkCollectionInfo struct {
- UUID string `json:"uuid"`
- OwnerUUID string `json:"owner_uuid"`
- ReplicationDesired int `json:"replication_desired"`
- ModifiedAt time.Time `json:"modified_at"`
- ManifestText string `json:"manifest_text"`
-}
-
-// SdkCollectionList lists collections from api
-type SdkCollectionList struct {
- ItemsAvailable int `json:"items_available"`
- Items []SdkCollectionInfo `json:"items"`
-}
-
-func init() {
- flag.StringVar(&HeapProfileFilename,
- "heap-profile",
- "",
- "File to write the heap profiles to. Leave blank to skip profiling.")
-}
-
-// WriteHeapProfile writes the heap profile to a file for later review.
-// Since a file is expected to only contain a single heap profile this
-// function overwrites the previously written profile, so it is safe
-// to call multiple times in a single run.
-// Otherwise we would see cumulative numbers as explained here:
-// https://groups.google.com/d/msg/golang-nuts/ZyHciRglQYc/2nh4Ndu2fZcJ
-func WriteHeapProfile() error {
- if HeapProfileFilename != "" {
- heapProfile, err := os.Create(HeapProfileFilename)
- if err != nil {
- return err
- }
-
- defer heapProfile.Close()
-
- err = pprof.WriteHeapProfile(heapProfile)
- return err
- }
-
- return nil
-}
-
-// GetCollectionsAndSummarize gets collections from api and summarizes
-func GetCollectionsAndSummarize(params GetCollectionsParams) (results ReadCollections, err error) {
- results, err = GetCollections(params)
- if err != nil {
- return
- }
-
- results.Summarize(params.Logger)
-
- log.Printf("Uuid to Size used: %v", results.OwnerToCollectionSize)
- log.Printf("Read and processed %d collections",
- len(results.UUIDToCollection))
-
- // TODO(misha): Add a "readonly" flag. If we're in readonly mode,
- // lots of behaviors can become warnings (and obviously we can't
- // write anything).
- // if !readCollections.ReadAllCollections {
- // log.Fatalf("Did not read all collections")
- // }
-
- return
-}
-
-// GetCollections gets collections from api
-func GetCollections(params GetCollectionsParams) (results ReadCollections, err error) {
- if ¶ms.Client == nil {
- err = fmt.Errorf("params.Client passed to GetCollections() should " +
- "contain a valid ArvadosClient, but instead it is nil.")
- return
- }
-
- fieldsWanted := []string{"manifest_text",
- "owner_uuid",
- "uuid",
- "replication_desired",
- "modified_at"}
-
- sdkParams := arvadosclient.Dict{
- "select": fieldsWanted,
- "order": []string{"modified_at ASC", "uuid ASC"},
- "filters": [][]string{{"modified_at", ">=", "1900-01-01T00:00:00Z"}},
- "offset": 0}
-
- if params.BatchSize > 0 {
- sdkParams["limit"] = params.BatchSize
- }
-
- var defaultReplicationLevel int
- {
- var value interface{}
- value, err = params.Client.Discovery("defaultCollectionReplication")
- if err != nil {
- return
- }
-
- defaultReplicationLevel = int(value.(float64))
- if defaultReplicationLevel <= 0 {
- err = fmt.Errorf("Default collection replication returned by arvados SDK "+
- "should be a positive integer but instead it was %d.",
- defaultReplicationLevel)
- return
- }
- }
-
- initialNumberOfCollectionsAvailable, err :=
- util.NumberItemsAvailable(params.Client, "collections")
- if err != nil {
- return
- }
- // Include a 1% margin for collections added while we're reading so
- // that we don't have to grow the map in most cases.
- maxExpectedCollections := int(
- float64(initialNumberOfCollectionsAvailable) * 1.01)
- results.UUIDToCollection = make(map[string]Collection, maxExpectedCollections)
-
- if params.Logger != nil {
- params.Logger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- collectionInfo := logger.GetOrCreateMap(p, "collection_info")
- collectionInfo["num_collections_at_start"] = initialNumberOfCollectionsAvailable
- collectionInfo["batch_size"] = params.BatchSize
- collectionInfo["default_replication_level"] = defaultReplicationLevel
- })
- }
-
- // These values are just for getting the loop to run the first time,
- // afterwards they'll be set to real values.
- remainingCollections := 1
- var totalCollections int
- var previousTotalCollections int
- for remainingCollections > 0 {
- // We're still finding new collections
-
- // Write the heap profile for examining memory usage
- err = WriteHeapProfile()
- if err != nil {
- return
- }
-
- // Get next batch of collections.
- var collections SdkCollectionList
- err = params.Client.List("collections", sdkParams, &collections)
- if err != nil {
- return
- }
- batchCollections := len(collections.Items)
-
- // We must always have at least one collection in the batch
- if batchCollections < 1 {
- err = fmt.Errorf("API query returned no collections for %+v", sdkParams)
- return
- }
-
- // Update count of remaining collections
- remainingCollections = collections.ItemsAvailable - sdkParams["offset"].(int) - batchCollections
-
- // Process collection and update our date filter.
- latestModificationDate, maxManifestSize, totalManifestSize, err := ProcessCollections(params.Logger,
- collections.Items,
- defaultReplicationLevel,
- results.UUIDToCollection)
- if err != nil {
- return results, err
- }
- if sdkParams["filters"].([][]string)[0][2] != latestModificationDate.Format(time.RFC3339) {
- sdkParams["filters"].([][]string)[0][2] = latestModificationDate.Format(time.RFC3339)
- sdkParams["offset"] = 0
- } else {
- sdkParams["offset"] = sdkParams["offset"].(int) + batchCollections
- }
-
- // update counts
- previousTotalCollections = totalCollections
- totalCollections = len(results.UUIDToCollection)
-
- log.Printf("%d collections read, %d (%d new) in last batch, "+
- "%d remaining, "+
- "%s latest modified date, %.0f %d %d avg,max,total manifest size",
- totalCollections,
- batchCollections,
- totalCollections-previousTotalCollections,
- remainingCollections,
- sdkParams["filters"].([][]string)[0][2],
- float32(totalManifestSize)/float32(totalCollections),
- maxManifestSize, totalManifestSize)
-
- if params.Logger != nil {
- params.Logger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- collectionInfo := logger.GetOrCreateMap(p, "collection_info")
- collectionInfo["collections_read"] = totalCollections
- collectionInfo["latest_modified_date_seen"] = sdkParams["filters"].([][]string)[0][2]
- collectionInfo["total_manifest_size"] = totalManifestSize
- collectionInfo["max_manifest_size"] = maxManifestSize
- })
- }
- }
-
- // Make one final API request to verify that we have processed all collections available up to the latest modification date
- var collections SdkCollectionList
- sdkParams["filters"].([][]string)[0][1] = "<="
- sdkParams["limit"] = 0
- err = params.Client.List("collections", sdkParams, &collections)
- if err != nil {
- return
- }
- finalNumberOfCollectionsAvailable, err :=
- util.NumberItemsAvailable(params.Client, "collections")
- if err != nil {
- return
- }
- if totalCollections < finalNumberOfCollectionsAvailable {
- err = fmt.Errorf("API server indicates a total of %d collections "+
- "available up to %v, but we only retrieved %d. "+
- "Refusing to continue as this could indicate an "+
- "otherwise undetected failure.",
- finalNumberOfCollectionsAvailable,
- sdkParams["filters"].([][]string)[0][2],
- totalCollections)
- return
- }
-
- // Write the heap profile for examining memory usage
- err = WriteHeapProfile()
-
- return
-}
-
-// StrCopy returns a newly allocated string.
-// It is useful to copy slices so that the garbage collector can reuse
-// the memory of the longer strings they came from.
-func StrCopy(s string) string {
- return string([]byte(s))
-}
-
-// ProcessCollections read from api server
-func ProcessCollections(arvLogger *logger.Logger,
- receivedCollections []SdkCollectionInfo,
- defaultReplicationLevel int,
- UUIDToCollection map[string]Collection,
-) (
- latestModificationDate time.Time,
- maxManifestSize, totalManifestSize uint64,
- err error,
-) {
- for _, sdkCollection := range receivedCollections {
- collection := Collection{UUID: StrCopy(sdkCollection.UUID),
- OwnerUUID: StrCopy(sdkCollection.OwnerUUID),
- ReplicationLevel: sdkCollection.ReplicationDesired,
- BlockDigestToSize: make(map[blockdigest.BlockDigest]int)}
-
- if sdkCollection.ModifiedAt.IsZero() {
- err = fmt.Errorf(
- "Arvados SDK collection returned with unexpected zero "+
- "modification date. This probably means that either we failed to "+
- "parse the modification date or the API server has changed how "+
- "it returns modification dates: %+v",
- collection)
- return
- }
-
- if sdkCollection.ModifiedAt.After(latestModificationDate) {
- latestModificationDate = sdkCollection.ModifiedAt
- }
-
- if collection.ReplicationLevel == 0 {
- collection.ReplicationLevel = defaultReplicationLevel
- }
-
- manifest := manifest.Manifest{Text: sdkCollection.ManifestText}
- manifestSize := uint64(len(sdkCollection.ManifestText))
-
- if _, alreadySeen := UUIDToCollection[collection.UUID]; !alreadySeen {
- totalManifestSize += manifestSize
- }
- if manifestSize > maxManifestSize {
- maxManifestSize = manifestSize
- }
-
- blockChannel := manifest.BlockIterWithDuplicates()
- for block := range blockChannel {
- if storedSize, stored := collection.BlockDigestToSize[block.Digest]; stored && storedSize != block.Size {
- log.Printf(
- "Collection %s contains multiple sizes (%d and %d) for block %s",
- collection.UUID,
- storedSize,
- block.Size,
- block.Digest)
- }
- collection.BlockDigestToSize[block.Digest] = block.Size
- }
- if manifest.Err != nil {
- err = manifest.Err
- return
- }
-
- collection.TotalSize = 0
- for _, size := range collection.BlockDigestToSize {
- collection.TotalSize += size
- }
- UUIDToCollection[collection.UUID] = collection
-
- // Clear out all the manifest strings that we don't need anymore.
- // These hopefully form the bulk of our memory usage.
- manifest.Text = ""
- sdkCollection.ManifestText = ""
- }
-
- return
-}
-
-// Summarize the collections read
-func (readCollections *ReadCollections) Summarize(arvLogger *logger.Logger) {
- readCollections.OwnerToCollectionSize = make(map[string]int)
- readCollections.BlockToDesiredReplication = make(map[blockdigest.DigestWithSize]int)
- numCollections := len(readCollections.UUIDToCollection)
- readCollections.CollectionUUIDToIndex = make(map[string]int, numCollections)
- readCollections.CollectionIndexToUUID = make([]string, 0, numCollections)
- readCollections.BlockToCollectionIndices = make(map[blockdigest.DigestWithSize][]int)
-
- for _, coll := range readCollections.UUIDToCollection {
- collectionIndex := len(readCollections.CollectionIndexToUUID)
- readCollections.CollectionIndexToUUID =
- append(readCollections.CollectionIndexToUUID, coll.UUID)
- readCollections.CollectionUUIDToIndex[coll.UUID] = collectionIndex
-
- readCollections.OwnerToCollectionSize[coll.OwnerUUID] =
- readCollections.OwnerToCollectionSize[coll.OwnerUUID] + coll.TotalSize
-
- for block, size := range coll.BlockDigestToSize {
- locator := blockdigest.DigestWithSize{Digest: block, Size: uint32(size)}
- readCollections.BlockToCollectionIndices[locator] =
- append(readCollections.BlockToCollectionIndices[locator],
- collectionIndex)
- storedReplication := readCollections.BlockToDesiredReplication[locator]
- if coll.ReplicationLevel > storedReplication {
- readCollections.BlockToDesiredReplication[locator] =
- coll.ReplicationLevel
- }
- }
- }
-
- if arvLogger != nil {
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- collectionInfo := logger.GetOrCreateMap(p, "collection_info")
- // Since maps are shallow copied, we run a risk of concurrent
- // updates here. By copying results.OwnerToCollectionSize into
- // the log, we're assuming that it won't be updated.
- collectionInfo["owner_to_collection_size"] =
- readCollections.OwnerToCollectionSize
- collectionInfo["distinct_blocks_named"] =
- len(readCollections.BlockToDesiredReplication)
- })
- }
-
- return
-}
+++ /dev/null
-package collection
-
-import (
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/arvadostest"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- . "gopkg.in/check.v1"
- "net/http"
- "net/http/httptest"
- "testing"
-)
-
-// Gocheck boilerplate
-func Test(t *testing.T) {
- TestingT(t)
-}
-
-type MySuite struct{}
-
-var _ = Suite(&MySuite{})
-
-// This captures the result we expect from
-// ReadCollections.Summarize(). Because CollectionUUIDToIndex is
-// indeterminate, we replace BlockToCollectionIndices with
-// BlockToCollectionUuids.
-type ExpectedSummary struct {
- OwnerToCollectionSize map[string]int
- BlockToDesiredReplication map[blockdigest.DigestWithSize]int
- BlockToCollectionUuids map[blockdigest.DigestWithSize][]string
-}
-
-func CompareSummarizedReadCollections(c *C,
- summarized ReadCollections,
- expected ExpectedSummary) {
-
- c.Assert(summarized.OwnerToCollectionSize, DeepEquals,
- expected.OwnerToCollectionSize)
-
- c.Assert(summarized.BlockToDesiredReplication, DeepEquals,
- expected.BlockToDesiredReplication)
-
- summarizedBlockToCollectionUuids :=
- make(map[blockdigest.DigestWithSize]map[string]struct{})
- for digest, indices := range summarized.BlockToCollectionIndices {
- uuidSet := make(map[string]struct{})
- summarizedBlockToCollectionUuids[digest] = uuidSet
- for _, index := range indices {
- uuidSet[summarized.CollectionIndexToUUID[index]] = struct{}{}
- }
- }
-
- expectedBlockToCollectionUuids :=
- make(map[blockdigest.DigestWithSize]map[string]struct{})
- for digest, uuidSlice := range expected.BlockToCollectionUuids {
- uuidSet := make(map[string]struct{})
- expectedBlockToCollectionUuids[digest] = uuidSet
- for _, uuid := range uuidSlice {
- uuidSet[uuid] = struct{}{}
- }
- }
-
- c.Assert(summarizedBlockToCollectionUuids, DeepEquals,
- expectedBlockToCollectionUuids)
-}
-
-func (s *MySuite) TestSummarizeSimple(checker *C) {
- rc := MakeTestReadCollections([]TestCollectionSpec{{
- ReplicationLevel: 5,
- Blocks: []int{1, 2},
- }})
-
- rc.Summarize(nil)
-
- c := rc.UUIDToCollection["col0"]
-
- blockDigest1 := blockdigest.MakeTestDigestWithSize(1)
- blockDigest2 := blockdigest.MakeTestDigestWithSize(2)
-
- expected := ExpectedSummary{
- OwnerToCollectionSize: map[string]int{c.OwnerUUID: c.TotalSize},
- BlockToDesiredReplication: map[blockdigest.DigestWithSize]int{blockDigest1: 5, blockDigest2: 5},
- BlockToCollectionUuids: map[blockdigest.DigestWithSize][]string{blockDigest1: {c.UUID}, blockDigest2: {c.UUID}},
- }
-
- CompareSummarizedReadCollections(checker, rc, expected)
-}
-
-func (s *MySuite) TestSummarizeOverlapping(checker *C) {
- rc := MakeTestReadCollections([]TestCollectionSpec{
- {
- ReplicationLevel: 5,
- Blocks: []int{1, 2},
- },
- {
- ReplicationLevel: 8,
- Blocks: []int{2, 3},
- },
- })
-
- rc.Summarize(nil)
-
- c0 := rc.UUIDToCollection["col0"]
- c1 := rc.UUIDToCollection["col1"]
-
- blockDigest1 := blockdigest.MakeTestDigestWithSize(1)
- blockDigest2 := blockdigest.MakeTestDigestWithSize(2)
- blockDigest3 := blockdigest.MakeTestDigestWithSize(3)
-
- expected := ExpectedSummary{
- OwnerToCollectionSize: map[string]int{
- c0.OwnerUUID: c0.TotalSize,
- c1.OwnerUUID: c1.TotalSize,
- },
- BlockToDesiredReplication: map[blockdigest.DigestWithSize]int{
- blockDigest1: 5,
- blockDigest2: 8,
- blockDigest3: 8,
- },
- BlockToCollectionUuids: map[blockdigest.DigestWithSize][]string{
- blockDigest1: {c0.UUID},
- blockDigest2: {c0.UUID, c1.UUID},
- blockDigest3: {c1.UUID},
- },
- }
-
- CompareSummarizedReadCollections(checker, rc, expected)
-}
-
-type APITestData struct {
- // path and response map
- responses map[string]arvadostest.StubResponse
-
- // expected error, if any
- expectedError string
-}
-
-func (s *MySuite) TestGetCollectionsAndSummarize_DiscoveryError(c *C) {
- testGetCollectionsAndSummarize(c,
- APITestData{
- responses: make(map[string]arvadostest.StubResponse),
- expectedError: "arvados API server error: 500.*",
- })
-}
-
-func (s *MySuite) TestGetCollectionsAndSummarize_ApiErrorGetCollections(c *C) {
- respMap := make(map[string]arvadostest.StubResponse)
- respMap["/discovery/v1/apis/arvados/v1/rest"] = arvadostest.StubResponse{200, `{"defaultCollectionReplication":2}`}
- respMap["/arvados/v1/collections"] = arvadostest.StubResponse{-1, ``}
-
- testGetCollectionsAndSummarize(c,
- APITestData{
- responses: respMap,
- expectedError: "arvados API server error: 302.*",
- })
-}
-
-func (s *MySuite) TestGetCollectionsAndSummarize_GetCollectionsBadStreamName(c *C) {
- respMap := make(map[string]arvadostest.StubResponse)
- respMap["/discovery/v1/apis/arvados/v1/rest"] = arvadostest.StubResponse{200, `{"defaultCollectionReplication":2}`}
- respMap["/arvados/v1/collections"] = arvadostest.StubResponse{200, `{"items_available":1,"items":[{"modified_at":"2015-11-24T15:04:05Z","manifest_text":"badstreamname"}]}`}
-
- testGetCollectionsAndSummarize(c,
- APITestData{
- responses: respMap,
- expectedError: "Invalid stream name: badstreamname",
- })
-}
-
-func (s *MySuite) TestGetCollectionsAndSummarize_GetCollectionsBadFileToken(c *C) {
- respMap := make(map[string]arvadostest.StubResponse)
- respMap["/discovery/v1/apis/arvados/v1/rest"] = arvadostest.StubResponse{200, `{"defaultCollectionReplication":2}`}
- respMap["/arvados/v1/collections"] = arvadostest.StubResponse{200, `{"items_available":1,"items":[{"modified_at":"2015-11-24T15:04:05Z","manifest_text":"./goodstream acbd18db4cc2f85cedef654fccc4a4d8+3 0:1:file1.txt file2.txt"}]}`}
-
- testGetCollectionsAndSummarize(c,
- APITestData{
- responses: respMap,
- expectedError: "Invalid file token: file2.txt",
- })
-}
-
-func testGetCollectionsAndSummarize(c *C, testData APITestData) {
- apiStub := arvadostest.ServerStub{testData.responses}
-
- api := httptest.NewServer(&apiStub)
- defer api.Close()
-
- arv := &arvadosclient.ArvadosClient{
- Scheme: "http",
- ApiServer: api.URL[7:],
- ApiToken: "abc123",
- Client: &http.Client{Transport: &http.Transport{}},
- }
-
- // GetCollectionsAndSummarize
- _, err := GetCollectionsAndSummarize(GetCollectionsParams{arv, nil, 10})
-
- if testData.expectedError == "" {
- c.Assert(err, IsNil)
- } else {
- c.Assert(err, ErrorMatches, testData.expectedError)
- }
-}
+++ /dev/null
-// Code used for testing only.
-
-package collection
-
-import (
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
-)
-
-// TestCollectionSpec with test blocks and desired replication level
-type TestCollectionSpec struct {
- // The desired replication level
- ReplicationLevel int
- // Blocks this contains, represented by ints. Ints repeated will
- // still only represent one block
- Blocks []int
-}
-
-// MakeTestReadCollections creates a ReadCollections object for testing
-// based on the give specs. Only the ReadAllCollections and UUIDToCollection
-// fields are populated. To populate other fields call rc.Summarize().
-func MakeTestReadCollections(specs []TestCollectionSpec) (rc ReadCollections) {
- rc = ReadCollections{
- ReadAllCollections: true,
- UUIDToCollection: map[string]Collection{},
- }
-
- for i, spec := range specs {
- c := Collection{
- UUID: fmt.Sprintf("col%d", i),
- OwnerUUID: fmt.Sprintf("owner%d", i),
- ReplicationLevel: spec.ReplicationLevel,
- BlockDigestToSize: map[blockdigest.BlockDigest]int{},
- }
- rc.UUIDToCollection[c.UUID] = c
- for _, j := range spec.Blocks {
- c.BlockDigestToSize[blockdigest.MakeTestBlockDigest(j)] = j
- }
- // We compute the size in a separate loop because the value
- // computed in the above loop would be invalid if c.Blocks
- // contained duplicates.
- for _, size := range c.BlockDigestToSize {
- c.TotalSize += size
- }
- }
- return
-}
-
-// CollectionIndicesForTesting returns a slice giving the collection
-// index of each collection that was passed in to MakeTestReadCollections.
-// rc.Summarize() must be called before this method, since Summarize()
-// assigns an index to each collection.
-func (rc ReadCollections) CollectionIndicesForTesting() (indices []int) {
- // TODO(misha): Assert that rc.Summarize() has been called.
- numCollections := len(rc.CollectionIndexToUUID)
- indices = make([]int, numCollections)
- for i := 0; i < numCollections; i++ {
- indices[i] = rc.CollectionUUIDToIndex[fmt.Sprintf("col%d", i)]
- }
- return
-}
+++ /dev/null
-/* Keep Datamanager. Responsible for checking on and reporting on Keep Storage */
-
-package main
-
-import (
- "errors"
- "flag"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "git.curoverse.com/arvados.git/sdk/go/util"
- "git.curoverse.com/arvados.git/services/datamanager/collection"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "git.curoverse.com/arvados.git/services/datamanager/loggerutil"
- "git.curoverse.com/arvados.git/services/datamanager/summary"
- "log"
- "time"
-)
-
-var (
- logEventTypePrefix string
- logFrequencySeconds int
- minutesBetweenRuns int
- collectionBatchSize int
- dryRun bool
-)
-
-func init() {
- flag.StringVar(&logEventTypePrefix,
- "log-event-type-prefix",
- "experimental-data-manager",
- "Prefix to use in the event_type of our arvados log entries. Set to empty to turn off logging")
- flag.IntVar(&logFrequencySeconds,
- "log-frequency-seconds",
- 20,
- "How frequently we'll write log entries in seconds.")
- flag.IntVar(&minutesBetweenRuns,
- "minutes-between-runs",
- 0,
- "How many minutes we wait between data manager runs. 0 means run once and exit.")
- flag.IntVar(&collectionBatchSize,
- "collection-batch-size",
- 1000,
- "How many collections to request in each batch.")
- flag.BoolVar(&dryRun,
- "dry-run",
- false,
- "Perform a dry run. Log how many blocks would be deleted/moved, but do not issue any changes to keepstore.")
-}
-
-func main() {
- flag.Parse()
-
- if minutesBetweenRuns == 0 {
- arv, err := arvadosclient.MakeArvadosClient()
- if err != nil {
- loggerutil.FatalWithMessage(arvLogger, fmt.Sprintf("Error making arvados client: %v", err))
- }
- err = singlerun(arv)
- if err != nil {
- loggerutil.FatalWithMessage(arvLogger, fmt.Sprintf("singlerun: %v", err))
- }
- } else {
- waitTime := time.Minute * time.Duration(minutesBetweenRuns)
- for {
- log.Println("Beginning Run")
- arv, err := arvadosclient.MakeArvadosClient()
- if err != nil {
- loggerutil.FatalWithMessage(arvLogger, fmt.Sprintf("Error making arvados client: %v", err))
- }
- err = singlerun(arv)
- if err != nil {
- log.Printf("singlerun: %v", err)
- }
- log.Printf("Sleeping for %d minutes", minutesBetweenRuns)
- time.Sleep(waitTime)
- }
- }
-}
-
-var arvLogger *logger.Logger
-
-func singlerun(arv *arvadosclient.ArvadosClient) error {
- var err error
- if isAdmin, err := util.UserIsAdmin(arv); err != nil {
- return errors.New("Error verifying admin token: " + err.Error())
- } else if !isAdmin {
- return errors.New("Current user is not an admin. Datamanager requires a privileged token.")
- }
-
- if logEventTypePrefix != "" {
- arvLogger, err = logger.NewLogger(logger.LoggerParams{
- Client: arv,
- EventTypePrefix: logEventTypePrefix,
- WriteInterval: time.Second * time.Duration(logFrequencySeconds)})
- }
-
- loggerutil.LogRunInfo(arvLogger)
- if arvLogger != nil {
- arvLogger.AddWriteHook(loggerutil.LogMemoryAlloc)
- }
-
- var (
- dataFetcher summary.DataFetcher
- readCollections collection.ReadCollections
- keepServerInfo keep.ReadServers
- )
-
- if summary.ShouldReadData() {
- dataFetcher = summary.ReadData
- } else {
- dataFetcher = BuildDataFetcher(arv)
- }
-
- err = dataFetcher(arvLogger, &readCollections, &keepServerInfo)
- if err != nil {
- return err
- }
-
- err = summary.MaybeWriteData(arvLogger, readCollections, keepServerInfo)
- if err != nil {
- return err
- }
-
- buckets := summary.BucketReplication(readCollections, keepServerInfo)
- bucketCounts := buckets.Counts()
-
- replicationSummary := buckets.SummarizeBuckets(readCollections)
- replicationCounts := replicationSummary.ComputeCounts()
-
- log.Printf("Blocks In Collections: %d, "+
- "\nBlocks In Keep: %d.",
- len(readCollections.BlockToDesiredReplication),
- len(keepServerInfo.BlockToServers))
- log.Println(replicationCounts.PrettyPrint())
-
- log.Printf("Blocks Histogram:")
- for _, rlbss := range bucketCounts {
- log.Printf("%+v: %10d",
- rlbss.Levels,
- rlbss.Count)
- }
-
- kc, err := keepclient.MakeKeepClient(arv)
- if err != nil {
- return fmt.Errorf("Error setting up keep client %v", err.Error())
- }
-
- // Log that we're finished. We force the recording, since go will
- // not wait for the write timer before exiting.
- if arvLogger != nil {
- defer arvLogger.FinalUpdate(func(p map[string]interface{}, e map[string]interface{}) {
- summaryInfo := logger.GetOrCreateMap(p, "summary_info")
- summaryInfo["block_replication_counts"] = bucketCounts
- summaryInfo["replication_summary"] = replicationCounts
- p["summary_info"] = summaryInfo
-
- p["run_info"].(map[string]interface{})["finished_at"] = time.Now()
- })
- }
-
- pullServers := summary.ComputePullServers(kc,
- &keepServerInfo,
- readCollections.BlockToDesiredReplication,
- replicationSummary.UnderReplicatedBlocks)
-
- pullLists := summary.BuildPullLists(pullServers)
-
- trashLists, trashErr := summary.BuildTrashLists(kc,
- &keepServerInfo,
- replicationSummary.KeepBlocksNotInCollections)
-
- err = summary.WritePullLists(arvLogger, pullLists, dryRun)
- if err != nil {
- return err
- }
-
- if trashErr != nil {
- return err
- }
- keep.SendTrashLists(arvLogger, kc, trashLists, dryRun)
-
- return nil
-}
-
-// BuildDataFetcher returns a data fetcher that fetches data from remote servers.
-func BuildDataFetcher(arv *arvadosclient.ArvadosClient) summary.DataFetcher {
- return func(
- arvLogger *logger.Logger,
- readCollections *collection.ReadCollections,
- keepServerInfo *keep.ReadServers,
- ) error {
- collDone := make(chan struct{})
- var collErr error
- go func() {
- *readCollections, collErr = collection.GetCollectionsAndSummarize(
- collection.GetCollectionsParams{
- Client: arv,
- Logger: arvLogger,
- BatchSize: collectionBatchSize})
- collDone <- struct{}{}
- }()
-
- var keepErr error
- *keepServerInfo, keepErr = keep.GetKeepServersAndSummarize(
- keep.GetKeepServersParams{
- Client: arv,
- Logger: arvLogger,
- Limit: 1000})
-
- <-collDone
-
- // Return a nil error only if both parts succeeded.
- if collErr != nil {
- return collErr
- }
- return keepErr
- }
-}
+++ /dev/null
-package main
-
-import (
- "encoding/json"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/arvadostest"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
- "git.curoverse.com/arvados.git/services/datamanager/collection"
- "git.curoverse.com/arvados.git/services/datamanager/summary"
- "io/ioutil"
- "net/http"
- "os"
- "os/exec"
- "path"
- "regexp"
- "strings"
- "testing"
- "time"
-)
-
-var arv *arvadosclient.ArvadosClient
-var keepClient *keepclient.KeepClient
-var keepServers []string
-
-func SetupDataManagerTest(t *testing.T) {
- os.Setenv("ARVADOS_API_HOST_INSECURE", "true")
-
- // start api and keep servers
- arvadostest.ResetEnv()
- arvadostest.StartAPI()
- arvadostest.StartKeep(2, false)
-
- var err error
- arv, err = arvadosclient.MakeArvadosClient()
- if err != nil {
- t.Fatalf("Error making arvados client: %s", err)
- }
- arv.ApiToken = arvadostest.DataManagerToken
-
- // keep client
- keepClient = &keepclient.KeepClient{
- Arvados: arv,
- Want_replicas: 2,
- Client: &http.Client{},
- }
-
- // discover keep services
- if err = keepClient.DiscoverKeepServers(); err != nil {
- t.Fatalf("Error discovering keep services: %s", err)
- }
- keepServers = []string{}
- for _, host := range keepClient.LocalRoots() {
- keepServers = append(keepServers, host)
- }
-}
-
-func TearDownDataManagerTest(t *testing.T) {
- arvadostest.StopKeep(2)
- arvadostest.StopAPI()
- summary.WriteDataTo = ""
- collection.HeapProfileFilename = ""
-}
-
-func putBlock(t *testing.T, data string) string {
- locator, _, err := keepClient.PutB([]byte(data))
- if err != nil {
- t.Fatalf("Error putting test data for %s %s %v", data, locator, err)
- }
- if locator == "" {
- t.Fatalf("No locator found after putting test data")
- }
-
- splits := strings.Split(locator, "+")
- return splits[0] + "+" + splits[1]
-}
-
-func getBlock(t *testing.T, locator string, data string) {
- reader, blocklen, _, err := keepClient.Get(locator)
- if err != nil {
- t.Fatalf("Error getting test data in setup for %s %s %v", data, locator, err)
- }
- if reader == nil {
- t.Fatalf("No reader found after putting test data")
- }
- if blocklen != int64(len(data)) {
- t.Fatalf("blocklen %d did not match data len %d", blocklen, len(data))
- }
-
- all, err := ioutil.ReadAll(reader)
- if string(all) != data {
- t.Fatalf("Data read %s did not match expected data %s", string(all), data)
- }
-}
-
-// Create a collection using arv-put
-func createCollection(t *testing.T, data string) string {
- tempfile, err := ioutil.TempFile(os.TempDir(), "temp-test-file")
- defer os.Remove(tempfile.Name())
-
- _, err = tempfile.Write([]byte(data))
- if err != nil {
- t.Fatalf("Error writing to tempfile %v", err)
- }
-
- // arv-put
- output, err := exec.Command("arv-put", "--use-filename", "test.txt", tempfile.Name()).Output()
- if err != nil {
- t.Fatalf("Error running arv-put %s", err)
- }
-
- uuid := string(output[0:27]) // trim terminating char
- return uuid
-}
-
-// Get collection locator
-var locatorMatcher = regexp.MustCompile(`^([0-9a-f]{32})\+(\d*)(.*)$`)
-
-func getFirstLocatorFromCollection(t *testing.T, uuid string) string {
- manifest := getCollection(t, uuid)["manifest_text"].(string)
-
- locator := strings.Split(manifest, " ")[1]
- match := locatorMatcher.FindStringSubmatch(locator)
- if match == nil {
- t.Fatalf("No locator found in collection manifest %s", manifest)
- }
-
- return match[1] + "+" + match[2]
-}
-
-func switchToken(t string) func() {
- orig := arv.ApiToken
- restore := func() {
- arv.ApiToken = orig
- }
- arv.ApiToken = t
- return restore
-}
-
-func getCollection(t *testing.T, uuid string) Dict {
- defer switchToken(arvadostest.AdminToken)()
-
- getback := make(Dict)
- err := arv.Get("collections", uuid, nil, &getback)
- if err != nil {
- t.Fatalf("Error getting collection %s", err)
- }
- if getback["uuid"] != uuid {
- t.Fatalf("Get collection uuid did not match original: $s, result: $s", uuid, getback["uuid"])
- }
-
- return getback
-}
-
-func updateCollection(t *testing.T, uuid string, paramName string, paramValue string) {
- defer switchToken(arvadostest.AdminToken)()
-
- err := arv.Update("collections", uuid, arvadosclient.Dict{
- "collection": arvadosclient.Dict{
- paramName: paramValue,
- },
- }, &arvadosclient.Dict{})
-
- if err != nil {
- t.Fatalf("Error updating collection %s", err)
- }
-}
-
-type Dict map[string]interface{}
-
-func deleteCollection(t *testing.T, uuid string) {
- defer switchToken(arvadostest.AdminToken)()
-
- getback := make(Dict)
- err := arv.Delete("collections", uuid, nil, &getback)
- if err != nil {
- t.Fatalf("Error deleting collection %s", err)
- }
- if getback["uuid"] != uuid {
- t.Fatalf("Delete collection uuid did not match original: $s, result: $s", uuid, getback["uuid"])
- }
-}
-
-func dataManagerSingleRun(t *testing.T) {
- err := singlerun(arv)
- if err != nil {
- t.Fatalf("Error during singlerun %s", err)
- }
-}
-
-func getBlockIndexesForServer(t *testing.T, i int) []string {
- var indexes []string
-
- path := keepServers[i] + "/index"
- client := http.Client{}
- req, err := http.NewRequest("GET", path, nil)
- req.Header.Add("Authorization", "OAuth2 "+arvadostest.DataManagerToken)
- req.Header.Add("Content-Type", "application/octet-stream")
- resp, err := client.Do(req)
- defer resp.Body.Close()
-
- if err != nil {
- t.Fatalf("Error during %s %s", path, err)
- }
-
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- t.Fatalf("Error reading response from %s %s", path, err)
- }
-
- lines := strings.Split(string(body), "\n")
- for _, line := range lines {
- indexes = append(indexes, strings.Split(line, " ")...)
- }
-
- return indexes
-}
-
-func getBlockIndexes(t *testing.T) [][]string {
- var indexes [][]string
-
- for i := 0; i < len(keepServers); i++ {
- indexes = append(indexes, getBlockIndexesForServer(t, i))
- }
- return indexes
-}
-
-func verifyBlocks(t *testing.T, notExpected []string, expected []string, minReplication int) {
- blocks := getBlockIndexes(t)
-
- for _, block := range notExpected {
- for _, idx := range blocks {
- if valueInArray(block, idx) {
- t.Fatalf("Found unexpected block %s", block)
- }
- }
- }
-
- for _, block := range expected {
- nFound := 0
- for _, idx := range blocks {
- if valueInArray(block, idx) {
- nFound++
- }
- }
- if nFound < minReplication {
- t.Fatalf("Found %d replicas of block %s, expected >= %d", nFound, block, minReplication)
- }
- }
-}
-
-func valueInArray(value string, list []string) bool {
- for _, v := range list {
- if value == v {
- return true
- }
- }
- return false
-}
-
-// Test env uses two keep volumes. The volume names can be found by reading the files
-// ARVADOS_HOME/tmp/keep0.volume and ARVADOS_HOME/tmp/keep1.volume
-//
-// The keep volumes are of the dir structure: volumeN/subdir/locator
-func backdateBlocks(t *testing.T, oldUnusedBlockLocators []string) {
- // First get rid of any size hints in the locators
- var trimmedBlockLocators []string
- for _, block := range oldUnusedBlockLocators {
- trimmedBlockLocators = append(trimmedBlockLocators, strings.Split(block, "+")[0])
- }
-
- // Get the working dir so that we can read keep{n}.volume files
- wd, err := os.Getwd()
- if err != nil {
- t.Fatalf("Error getting working dir %s", err)
- }
-
- // Now cycle through the two keep volumes
- oldTime := time.Now().AddDate(0, -2, 0)
- for i := 0; i < 2; i++ {
- filename := fmt.Sprintf("%s/../../tmp/keep%d.volume", wd, i)
- volumeDir, err := ioutil.ReadFile(filename)
- if err != nil {
- t.Fatalf("Error reading keep volume file %s %s", filename, err)
- }
-
- // Read the keep volume dir structure
- volumeContents, err := ioutil.ReadDir(string(volumeDir))
- if err != nil {
- t.Fatalf("Error reading keep dir %s %s", string(volumeDir), err)
- }
-
- // Read each subdir for each of the keep volume dir
- for _, subdir := range volumeContents {
- subdirName := fmt.Sprintf("%s/%s", volumeDir, subdir.Name())
- subdirContents, err := ioutil.ReadDir(string(subdirName))
- if err != nil {
- t.Fatalf("Error reading keep dir %s %s", string(subdirName), err)
- }
-
- // Now we got to the files. The files are names are the block locators
- for _, fileInfo := range subdirContents {
- blockName := fileInfo.Name()
- myname := fmt.Sprintf("%s/%s", subdirName, blockName)
- if valueInArray(blockName, trimmedBlockLocators) {
- err = os.Chtimes(myname, oldTime, oldTime)
- }
- }
- }
- }
-}
-
-func getStatus(t *testing.T, path string) interface{} {
- client := http.Client{}
- req, err := http.NewRequest("GET", path, nil)
- req.Header.Add("Authorization", "OAuth2 "+arvadostest.DataManagerToken)
- req.Header.Add("Content-Type", "application/octet-stream")
- resp, err := client.Do(req)
- if err != nil {
- t.Fatalf("Error during %s %s", path, err)
- }
- defer resp.Body.Close()
-
- var s interface{}
- json.NewDecoder(resp.Body).Decode(&s)
-
- return s
-}
-
-// Wait until PullQueue and TrashQueue are empty on all keepServers.
-func waitUntilQueuesFinishWork(t *testing.T) {
- for _, ks := range keepServers {
- for done := false; !done; {
- time.Sleep(100 * time.Millisecond)
- s := getStatus(t, ks+"/status.json")
- for _, qName := range []string{"PullQueue", "TrashQueue"} {
- qStatus := s.(map[string]interface{})[qName].(map[string]interface{})
- if qStatus["Queued"].(float64)+qStatus["InProgress"].(float64) == 0 {
- done = true
- }
- }
- }
- }
-}
-
-// Create some blocks and backdate some of them.
-// Also create some collections and delete some of them.
-// Verify block indexes.
-func TestPutAndGetBlocks(t *testing.T) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- // Put some blocks which will be backdated later on
- // The first one will also be used in a collection and hence should not be deleted when datamanager runs.
- // The rest will be old and unreferenced and hence should be deleted when datamanager runs.
- var oldUnusedBlockLocators []string
- oldUnusedBlockData := "this block will have older mtime"
- for i := 0; i < 5; i++ {
- oldUnusedBlockLocators = append(oldUnusedBlockLocators, putBlock(t, fmt.Sprintf("%s%d", oldUnusedBlockData, i)))
- }
- for i := 0; i < 5; i++ {
- getBlock(t, oldUnusedBlockLocators[i], fmt.Sprintf("%s%d", oldUnusedBlockData, i))
- }
-
- // The rest will be old and unreferenced and hence should be deleted when datamanager runs.
- oldUsedBlockData := "this collection block will have older mtime"
- oldUsedBlockLocator := putBlock(t, oldUsedBlockData)
- getBlock(t, oldUsedBlockLocator, oldUsedBlockData)
-
- // Put some more blocks which will not be backdated; hence they are still new, but not in any collection.
- // Hence, even though unreferenced, these should not be deleted when datamanager runs.
- var newBlockLocators []string
- newBlockData := "this block is newer"
- for i := 0; i < 5; i++ {
- newBlockLocators = append(newBlockLocators, putBlock(t, fmt.Sprintf("%s%d", newBlockData, i)))
- }
- for i := 0; i < 5; i++ {
- getBlock(t, newBlockLocators[i], fmt.Sprintf("%s%d", newBlockData, i))
- }
-
- // Create a collection that would be deleted later on
- toBeDeletedCollectionUUID := createCollection(t, "some data for collection creation")
- toBeDeletedCollectionLocator := getFirstLocatorFromCollection(t, toBeDeletedCollectionUUID)
-
- // Create another collection that has the same data as the one of the old blocks
- oldUsedBlockCollectionUUID := createCollection(t, oldUsedBlockData)
- oldUsedBlockCollectionLocator := getFirstLocatorFromCollection(t, oldUsedBlockCollectionUUID)
- if oldUsedBlockCollectionLocator != oldUsedBlockLocator {
- t.Fatalf("Locator of the collection with the same data as old block is different %s", oldUsedBlockCollectionLocator)
- }
-
- // Create another collection whose replication level will be changed
- replicationCollectionUUID := createCollection(t, "replication level on this collection will be reduced")
- replicationCollectionLocator := getFirstLocatorFromCollection(t, replicationCollectionUUID)
-
- // Create two collections with same data; one will be deleted later on
- dataForTwoCollections := "one of these collections will be deleted"
- oneOfTwoWithSameDataUUID := createCollection(t, dataForTwoCollections)
- oneOfTwoWithSameDataLocator := getFirstLocatorFromCollection(t, oneOfTwoWithSameDataUUID)
- secondOfTwoWithSameDataUUID := createCollection(t, dataForTwoCollections)
- secondOfTwoWithSameDataLocator := getFirstLocatorFromCollection(t, secondOfTwoWithSameDataUUID)
- if oneOfTwoWithSameDataLocator != secondOfTwoWithSameDataLocator {
- t.Fatalf("Locators for both these collections expected to be same: %s %s", oneOfTwoWithSameDataLocator, secondOfTwoWithSameDataLocator)
- }
-
- // create collection with empty manifest text
- emptyBlockLocator := putBlock(t, "")
- emptyCollection := createCollection(t, "")
-
- // Verify blocks before doing any backdating / deleting.
- var expected []string
- expected = append(expected, oldUnusedBlockLocators...)
- expected = append(expected, newBlockLocators...)
- expected = append(expected, toBeDeletedCollectionLocator)
- expected = append(expected, replicationCollectionLocator)
- expected = append(expected, oneOfTwoWithSameDataLocator)
- expected = append(expected, secondOfTwoWithSameDataLocator)
- expected = append(expected, emptyBlockLocator)
-
- verifyBlocks(t, nil, expected, 2)
-
- // Run datamanager in singlerun mode
- dataManagerSingleRun(t)
- waitUntilQueuesFinishWork(t)
-
- verifyBlocks(t, nil, expected, 2)
-
- // Backdate the to-be old blocks and delete the collections
- backdateBlocks(t, oldUnusedBlockLocators)
- deleteCollection(t, toBeDeletedCollectionUUID)
- deleteCollection(t, secondOfTwoWithSameDataUUID)
- backdateBlocks(t, []string{emptyBlockLocator})
- deleteCollection(t, emptyCollection)
-
- // Run data manager again
- dataManagerSingleRun(t)
- waitUntilQueuesFinishWork(t)
-
- // Get block indexes and verify that all backdated blocks except the first one used in collection are not included.
- expected = expected[:0]
- expected = append(expected, oldUsedBlockLocator)
- expected = append(expected, newBlockLocators...)
- expected = append(expected, toBeDeletedCollectionLocator)
- expected = append(expected, oneOfTwoWithSameDataLocator)
- expected = append(expected, secondOfTwoWithSameDataLocator)
- expected = append(expected, emptyBlockLocator) // even when unreferenced, this remains
-
- verifyBlocks(t, oldUnusedBlockLocators, expected, 2)
-
- // Reduce desired replication on replicationCollectionUUID
- // collection, and verify that Data Manager does not reduce
- // actual replication any further than that. (It might not
- // reduce actual replication at all; that's OK for this test.)
-
- // Reduce desired replication level.
- updateCollection(t, replicationCollectionUUID, "replication_desired", "1")
- collection := getCollection(t, replicationCollectionUUID)
- if collection["replication_desired"].(interface{}) != float64(1) {
- t.Fatalf("After update replication_desired is not 1; instead it is %v", collection["replication_desired"])
- }
-
- // Verify data is currently overreplicated.
- verifyBlocks(t, nil, []string{replicationCollectionLocator}, 2)
-
- // Run data manager again
- dataManagerSingleRun(t)
- waitUntilQueuesFinishWork(t)
-
- // Verify data is not underreplicated.
- verifyBlocks(t, nil, []string{replicationCollectionLocator}, 1)
-
- // Verify *other* collections' data is not underreplicated.
- verifyBlocks(t, oldUnusedBlockLocators, expected, 2)
-}
-
-func TestDatamanagerSingleRunRepeatedly(t *testing.T) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- for i := 0; i < 10; i++ {
- err := singlerun(arv)
- if err != nil {
- t.Fatalf("Got an error during datamanager singlerun: %v", err)
- }
- }
-}
-
-func TestGetStatusRepeatedly(t *testing.T) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- for i := 0; i < 10; i++ {
- for j := 0; j < 2; j++ {
- s := getStatus(t, keepServers[j]+"/status.json")
-
- var pullQueueStatus interface{}
- pullQueueStatus = s.(map[string]interface{})["PullQueue"]
- var trashQueueStatus interface{}
- trashQueueStatus = s.(map[string]interface{})["TrashQueue"]
-
- if pullQueueStatus.(map[string]interface{})["Queued"] == nil ||
- pullQueueStatus.(map[string]interface{})["InProgress"] == nil ||
- trashQueueStatus.(map[string]interface{})["Queued"] == nil ||
- trashQueueStatus.(map[string]interface{})["InProgress"] == nil {
- t.Fatalf("PullQueue and TrashQueue status not found")
- }
-
- time.Sleep(100 * time.Millisecond)
- }
- }
-}
-
-func TestRunDatamanagerWithBogusServer(t *testing.T) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- arv.ApiServer = "bogus-server"
-
- err := singlerun(arv)
- if err == nil {
- t.Fatalf("Expected error during singlerun with bogus server")
- }
-}
-
-func TestRunDatamanagerAsNonAdminUser(t *testing.T) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- arv.ApiToken = arvadostest.ActiveToken
-
- err := singlerun(arv)
- if err == nil {
- t.Fatalf("Expected error during singlerun as non-admin user")
- }
-}
-
-func TestPutAndGetBlocks_NoErrorDuringSingleRun(t *testing.T) {
- testOldBlocksNotDeletedOnDataManagerError(t, "", "", false, false)
-}
-
-func TestPutAndGetBlocks_ErrorDuringGetCollectionsBadWriteTo(t *testing.T) {
- badpath, err := arvadostest.CreateBadPath()
- if err != nil {
- t.Fatalf(err.Error())
- }
- defer func() {
- err = arvadostest.DestroyBadPath(badpath)
- if err != nil {
- t.Fatalf(err.Error())
- }
- }()
- testOldBlocksNotDeletedOnDataManagerError(t, path.Join(badpath, "writetofile"), "", true, true)
-}
-
-func TestPutAndGetBlocks_ErrorDuringGetCollectionsBadHeapProfileFilename(t *testing.T) {
- badpath, err := arvadostest.CreateBadPath()
- if err != nil {
- t.Fatalf(err.Error())
- }
- defer func() {
- err = arvadostest.DestroyBadPath(badpath)
- if err != nil {
- t.Fatalf(err.Error())
- }
- }()
- testOldBlocksNotDeletedOnDataManagerError(t, "", path.Join(badpath, "heapprofilefile"), true, true)
-}
-
-// Create some blocks and backdate some of them.
-// Run datamanager while producing an error condition.
-// Verify that the blocks are hence not deleted.
-func testOldBlocksNotDeletedOnDataManagerError(t *testing.T, writeDataTo string, heapProfileFile string, expectError bool, expectOldBlocks bool) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- // Put some blocks and backdate them.
- var oldUnusedBlockLocators []string
- oldUnusedBlockData := "this block will have older mtime"
- for i := 0; i < 5; i++ {
- oldUnusedBlockLocators = append(oldUnusedBlockLocators, putBlock(t, fmt.Sprintf("%s%d", oldUnusedBlockData, i)))
- }
- backdateBlocks(t, oldUnusedBlockLocators)
-
- // Run data manager
- summary.WriteDataTo = writeDataTo
- collection.HeapProfileFilename = heapProfileFile
-
- err := singlerun(arv)
- if !expectError {
- if err != nil {
- t.Fatalf("Got an error during datamanager singlerun: %v", err)
- }
- } else {
- if err == nil {
- t.Fatalf("Expected error during datamanager singlerun")
- }
- }
- waitUntilQueuesFinishWork(t)
-
- // Get block indexes and verify that all backdated blocks are not/deleted as expected
- if expectOldBlocks {
- verifyBlocks(t, nil, oldUnusedBlockLocators, 2)
- } else {
- verifyBlocks(t, oldUnusedBlockLocators, nil, 2)
- }
-}
-
-// Create a collection with multiple streams and blocks
-func createMultiStreamBlockCollection(t *testing.T, data string, numStreams, numBlocks int) (string, []string) {
- defer switchToken(arvadostest.AdminToken)()
-
- manifest := ""
- locators := make(map[string]bool)
- for s := 0; s < numStreams; s++ {
- manifest += fmt.Sprintf("./stream%d ", s)
- for b := 0; b < numBlocks; b++ {
- locator, _, err := keepClient.PutB([]byte(fmt.Sprintf("%s in stream %d and block %d", data, s, b)))
- if err != nil {
- t.Fatalf("Error creating block %d in stream %d: %v", b, s, err)
- }
- locators[strings.Split(locator, "+A")[0]] = true
- manifest += locator + " "
- }
- manifest += "0:1:dummyfile.txt\n"
- }
-
- collection := make(Dict)
- err := arv.Create("collections",
- arvadosclient.Dict{"collection": arvadosclient.Dict{"manifest_text": manifest}},
- &collection)
-
- if err != nil {
- t.Fatalf("Error creating collection %v", err)
- }
-
- var locs []string
- for k := range locators {
- locs = append(locs, k)
- }
-
- return collection["uuid"].(string), locs
-}
-
-// Create collection with multiple streams and blocks; backdate the blocks and but do not delete the collection.
-// Also, create stray block and backdate it.
-// After datamanager run: expect blocks from the collection, but not the stray block.
-func TestManifestWithMultipleStreamsAndBlocks(t *testing.T) {
- testManifestWithMultipleStreamsAndBlocks(t, 100, 10, "", false)
-}
-
-// Same test as TestManifestWithMultipleStreamsAndBlocks with an additional
-// keepstore of a service type other than "disk". Only the "disk" type services
-// will be indexed by datamanager and hence should work the same way.
-func TestManifestWithMultipleStreamsAndBlocks_WithOneUnsupportedKeepServer(t *testing.T) {
- testManifestWithMultipleStreamsAndBlocks(t, 2, 2, "testblobstore", false)
-}
-
-// Test datamanager with dry-run. Expect no block to be deleted.
-func TestManifestWithMultipleStreamsAndBlocks_DryRun(t *testing.T) {
- testManifestWithMultipleStreamsAndBlocks(t, 2, 2, "", true)
-}
-
-func testManifestWithMultipleStreamsAndBlocks(t *testing.T, numStreams, numBlocks int, createExtraKeepServerWithType string, isDryRun bool) {
- defer TearDownDataManagerTest(t)
- SetupDataManagerTest(t)
-
- // create collection whose blocks will be backdated
- collectionWithOldBlocks, oldBlocks := createMultiStreamBlockCollection(t, "old block", numStreams, numBlocks)
- if collectionWithOldBlocks == "" {
- t.Fatalf("Failed to create collection with %d blocks", numStreams*numBlocks)
- }
- if len(oldBlocks) != numStreams*numBlocks {
- t.Fatalf("Not all blocks are created: expected %v, found %v", 1000, len(oldBlocks))
- }
-
- // create a stray block that will be backdated
- strayOldBlock := putBlock(t, "this stray block is old")
-
- expected := []string{strayOldBlock}
- expected = append(expected, oldBlocks...)
- verifyBlocks(t, nil, expected, 2)
-
- // Backdate old blocks; but the collection still references these blocks
- backdateBlocks(t, oldBlocks)
-
- // also backdate the stray old block
- backdateBlocks(t, []string{strayOldBlock})
-
- // If requested, create an extra keepserver with the given type
- // This should be ignored during indexing and hence not change the datamanager outcome
- var extraKeepServerUUID string
- if createExtraKeepServerWithType != "" {
- extraKeepServerUUID = addExtraKeepServer(t, createExtraKeepServerWithType)
- defer deleteExtraKeepServer(extraKeepServerUUID)
- }
-
- // run datamanager
- dryRun = isDryRun
- dataManagerSingleRun(t)
-
- if dryRun {
- // verify that all blocks, including strayOldBlock, are still to be found
- verifyBlocks(t, nil, expected, 2)
- } else {
- // verify that strayOldBlock is not to be found, but the collections blocks are still there
- verifyBlocks(t, []string{strayOldBlock}, oldBlocks, 2)
- }
-}
-
-// Add one more keepstore with the given service type
-func addExtraKeepServer(t *testing.T, serviceType string) string {
- defer switchToken(arvadostest.AdminToken)()
-
- extraKeepService := make(arvadosclient.Dict)
- err := arv.Create("keep_services",
- arvadosclient.Dict{"keep_service": arvadosclient.Dict{
- "service_host": "localhost",
- "service_port": "21321",
- "service_ssl_flag": false,
- "service_type": serviceType}},
- &extraKeepService)
- if err != nil {
- t.Fatal(err)
- }
-
- return extraKeepService["uuid"].(string)
-}
-
-func deleteExtraKeepServer(uuid string) {
- defer switchToken(arvadostest.AdminToken)()
- arv.Delete("keep_services", uuid, nil, nil)
-}
+++ /dev/null
-#! /usr/bin/env python
-
-import arvados
-
-import argparse
-import cgi
-import csv
-import json
-import logging
-import math
-import pprint
-import re
-import threading
-import urllib2
-
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
-from collections import defaultdict, Counter
-from functools import partial
-from operator import itemgetter
-from SocketServer import ThreadingMixIn
-
-arv = arvados.api('v1')
-
-# Adapted from http://stackoverflow.com/questions/4180980/formatting-data-quantity-capacity-as-string
-byteunits = ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')
-def fileSizeFormat(value):
- exponent = 0 if value == 0 else int(math.log(value, 1024))
- return "%7.2f %-3s" % (float(value) / pow(1024, exponent),
- byteunits[exponent])
-
-def percentageFloor(x):
- """ Returns a float which is the input rounded down to the neared 0.01.
-
-e.g. precentageFloor(0.941354) = 0.94
-"""
- return math.floor(x*100) / 100.0
-
-
-def byteSizeFromValidUuid(valid_uuid):
- return int(valid_uuid.split('+')[1])
-
-class maxdict(dict):
- """A dictionary that holds the largest value entered for each key."""
- def addValue(self, key, value):
- dict.__setitem__(self, key, max(dict.get(self, key), value))
- def addValues(self, kv_pairs):
- for key,value in kv_pairs:
- self.addValue(key, value)
- def addDict(self, d):
- self.addValues(d.items())
-
-class CollectionInfo:
- DEFAULT_PERSISTER_REPLICATION_LEVEL=2
- all_by_uuid = {}
-
- def __init__(self, uuid):
- if CollectionInfo.all_by_uuid.has_key(uuid):
- raise ValueError('Collection for uuid "%s" already exists.' % uuid)
- self.uuid = uuid
- self.block_uuids = set() # uuids of keep blocks in this collection
- self.reader_uuids = set() # uuids of users who can read this collection
- self.persister_uuids = set() # uuids of users who want this collection saved
- # map from user uuid to replication level they desire
- self.persister_replication = maxdict()
-
- # The whole api response in case we need anything else later.
- self.api_response = []
- CollectionInfo.all_by_uuid[uuid] = self
-
- def byteSize(self):
- return sum(map(byteSizeFromValidUuid, self.block_uuids))
-
- def __str__(self):
- return ('CollectionInfo uuid: %s\n'
- ' %d block(s) containing %s\n'
- ' reader_uuids: %s\n'
- ' persister_replication: %s' %
- (self.uuid,
- len(self.block_uuids),
- fileSizeFormat(self.byteSize()),
- pprint.pformat(self.reader_uuids, indent = 15),
- pprint.pformat(self.persister_replication, indent = 15)))
-
- @staticmethod
- def get(uuid):
- if not CollectionInfo.all_by_uuid.has_key(uuid):
- CollectionInfo(uuid)
- return CollectionInfo.all_by_uuid[uuid]
-
-
-def extractUuid(candidate):
- """ Returns a canonical (hash+size) uuid from a valid uuid, or None if candidate is not a valid uuid."""
- match = re.match('([0-9a-fA-F]{32}\+[0-9]+)(\+[^+]+)*$', candidate)
- return match and match.group(1)
-
-def checkUserIsAdmin():
- current_user = arv.users().current().execute()
-
- if not current_user['is_admin']:
- log.warning('Current user %s (%s - %s) does not have '
- 'admin access and will not see much of the data.',
- current_user['full_name'],
- current_user['email'],
- current_user['uuid'])
- if args.require_admin_user:
- log.critical('Exiting, rerun with --no-require-admin-user '
- 'if you wish to continue.')
- exit(1)
-
-def buildCollectionsList():
- if args.uuid:
- return [args.uuid,]
- else:
- collections_list_response = arv.collections().list(limit=args.max_api_results).execute()
-
- print ('Returned %d of %d collections.' %
- (len(collections_list_response['items']),
- collections_list_response['items_available']))
-
- return [item['uuid'] for item in collections_list_response['items']]
-
-
-def readCollections(collection_uuids):
- for collection_uuid in collection_uuids:
- collection_block_uuids = set()
- collection_response = arv.collections().get(uuid=collection_uuid).execute()
- collection_info = CollectionInfo.get(collection_uuid)
- collection_info.api_response = collection_response
- manifest_lines = collection_response['manifest_text'].split('\n')
-
- if args.verbose:
- print 'Manifest text for %s:' % collection_uuid
- pprint.pprint(manifest_lines)
-
- for manifest_line in manifest_lines:
- if manifest_line:
- manifest_tokens = manifest_line.split(' ')
- if args.verbose:
- print 'manifest tokens: ' + pprint.pformat(manifest_tokens)
- stream_name = manifest_tokens[0]
-
- line_block_uuids = set(filter(None,
- [extractUuid(candidate)
- for candidate in manifest_tokens[1:]]))
- collection_info.block_uuids.update(line_block_uuids)
-
- # file_tokens = [token
- # for token in manifest_tokens[1:]
- # if extractUuid(token) is None]
-
- # # Sort file tokens by start position in case they aren't already
- # file_tokens.sort(key=lambda file_token: int(file_token.split(':')[0]))
-
- # if args.verbose:
- # print 'line_block_uuids: ' + pprint.pformat(line_block_uuids)
- # print 'file_tokens: ' + pprint.pformat(file_tokens)
-
-
-def readLinks():
- link_classes = set()
-
- for collection_uuid,collection_info in CollectionInfo.all_by_uuid.items():
- # TODO(misha): We may not be seing all the links, but since items
- # available does not return an accurate number, I don't knos how
- # to confirm that we saw all of them.
- collection_links_response = arv.links().list(where={'head_uuid':collection_uuid}).execute()
- link_classes.update([link['link_class'] for link in collection_links_response['items']])
- for link in collection_links_response['items']:
- if link['link_class'] == 'permission':
- collection_info.reader_uuids.add(link['tail_uuid'])
- elif link['link_class'] == 'resources':
- replication_level = link['properties'].get(
- 'replication',
- CollectionInfo.DEFAULT_PERSISTER_REPLICATION_LEVEL)
- collection_info.persister_replication.addValue(
- link['tail_uuid'],
- replication_level)
- collection_info.persister_uuids.add(link['tail_uuid'])
-
- print 'Found the following link classes:'
- pprint.pprint(link_classes)
-
-def reportMostPopularCollections():
- most_popular_collections = sorted(
- CollectionInfo.all_by_uuid.values(),
- key=lambda info: len(info.reader_uuids) + 10 * len(info.persister_replication),
- reverse=True)[:10]
-
- print 'Most popular Collections:'
- for collection_info in most_popular_collections:
- print collection_info
-
-
-def buildMaps():
- for collection_uuid,collection_info in CollectionInfo.all_by_uuid.items():
- # Add the block holding the manifest itself for all calculations
- block_uuids = collection_info.block_uuids.union([collection_uuid,])
- for block_uuid in block_uuids:
- block_to_collections[block_uuid].add(collection_uuid)
- block_to_readers[block_uuid].update(collection_info.reader_uuids)
- block_to_persisters[block_uuid].update(collection_info.persister_uuids)
- block_to_persister_replication[block_uuid].addDict(
- collection_info.persister_replication)
- for reader_uuid in collection_info.reader_uuids:
- reader_to_collections[reader_uuid].add(collection_uuid)
- reader_to_blocks[reader_uuid].update(block_uuids)
- for persister_uuid in collection_info.persister_uuids:
- persister_to_collections[persister_uuid].add(collection_uuid)
- persister_to_blocks[persister_uuid].update(block_uuids)
-
-
-def itemsByValueLength(original):
- return sorted(original.items(),
- key=lambda item:len(item[1]),
- reverse=True)
-
-
-def reportBusiestUsers():
- busiest_readers = itemsByValueLength(reader_to_collections)
- print 'The busiest readers are:'
- for reader,collections in busiest_readers:
- print '%s reading %d collections.' % (reader, len(collections))
- busiest_persisters = itemsByValueLength(persister_to_collections)
- print 'The busiest persisters are:'
- for persister,collections in busiest_persisters:
- print '%s reading %d collections.' % (persister, len(collections))
-
-
-def blockDiskUsage(block_uuid):
- """Returns the disk usage of a block given its uuid.
-
- Will return 0 before reading the contents of the keep servers.
- """
- return byteSizeFromValidUuid(block_uuid) * block_to_replication[block_uuid]
-
-def blockPersistedUsage(user_uuid, block_uuid):
- return (byteSizeFromValidUuid(block_uuid) *
- block_to_persister_replication[block_uuid].get(user_uuid, 0))
-
-memo_computeWeightedReplicationCosts = {}
-def computeWeightedReplicationCosts(replication_levels):
- """Computes the relative cost of varied replication levels.
-
- replication_levels: a tuple of integers representing the desired
- replication level. If n users want a replication level of x then x
- should appear n times in replication_levels.
-
- Returns a dictionary from replication level to cost.
-
- The basic thinking is that the cost of replicating at level x should
- be shared by everyone who wants replication of level x or higher.
-
- For example, if we have two users who want 1 copy, one user who
- wants 3 copies and two users who want 6 copies:
- the input would be [1, 1, 3, 6, 6] (or any permutation)
-
- The cost of the first copy is shared by all 5 users, so they each
- pay 1 copy / 5 users = 0.2.
- The cost of the second and third copies shared by 3 users, so they
- each pay 2 copies / 3 users = 0.67 (plus the above costs)
- The cost of the fourth, fifth and sixth copies is shared by two
- users, so they each pay 3 copies / 2 users = 1.5 (plus the above costs)
-
- Here are some other examples:
- computeWeightedReplicationCosts([1,]) -> {1:1.0}
- computeWeightedReplicationCosts([2,]) -> {2:2.0}
- computeWeightedReplicationCosts([1,1]) -> {1:0.5}
- computeWeightedReplicationCosts([2,2]) -> {1:1.0}
- computeWeightedReplicationCosts([1,2]) -> {1:0.5,2:1.5}
- computeWeightedReplicationCosts([1,3]) -> {1:0.5,2:2.5}
- computeWeightedReplicationCosts([1,3,6,6,10]) -> {1:0.2,3:0.7,6:1.7,10:5.7}
- """
- replication_level_counts = sorted(Counter(replication_levels).items())
-
- memo_key = str(replication_level_counts)
-
- if not memo_key in memo_computeWeightedReplicationCosts:
- last_level = 0
- current_cost = 0
- total_interested = float(sum(map(itemgetter(1), replication_level_counts)))
- cost_for_level = {}
- for replication_level, count in replication_level_counts:
- copies_added = replication_level - last_level
- # compute marginal cost from last level and add it to the last cost
- current_cost += copies_added / total_interested
- cost_for_level[replication_level] = current_cost
- # update invariants
- last_level = replication_level
- total_interested -= count
- memo_computeWeightedReplicationCosts[memo_key] = cost_for_level
-
- return memo_computeWeightedReplicationCosts[memo_key]
-
-def blockPersistedWeightedUsage(user_uuid, block_uuid):
- persister_replication_for_block = block_to_persister_replication[block_uuid]
- user_replication = persister_replication_for_block[user_uuid]
- return (
- byteSizeFromValidUuid(block_uuid) *
- computeWeightedReplicationCosts(
- persister_replication_for_block.values())[user_replication])
-
-
-def computeUserStorageUsage():
- for user, blocks in reader_to_blocks.items():
- user_to_usage[user][UNWEIGHTED_READ_SIZE_COL] = sum(map(
- byteSizeFromValidUuid,
- blocks))
- user_to_usage[user][WEIGHTED_READ_SIZE_COL] = sum(map(
- lambda block_uuid:(float(byteSizeFromValidUuid(block_uuid))/
- len(block_to_readers[block_uuid])),
- blocks))
- for user, blocks in persister_to_blocks.items():
- user_to_usage[user][UNWEIGHTED_PERSIST_SIZE_COL] = sum(map(
- partial(blockPersistedUsage, user),
- blocks))
- user_to_usage[user][WEIGHTED_PERSIST_SIZE_COL] = sum(map(
- partial(blockPersistedWeightedUsage, user),
- blocks))
-
-def printUserStorageUsage():
- print ('user: unweighted readable block size, weighted readable block size, '
- 'unweighted persisted block size, weighted persisted block size:')
- for user, usage in user_to_usage.items():
- print ('%s: %s %s %s %s' %
- (user,
- fileSizeFormat(usage[UNWEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[UNWEIGHTED_PERSIST_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_PERSIST_SIZE_COL])))
-
-def logUserStorageUsage():
- for user, usage in user_to_usage.items():
- body = {}
- # user could actually represent a user or a group. We don't set
- # the object_type field since we don't know which we have.
- body['object_uuid'] = user
- body['event_type'] = args.user_storage_log_event_type
- properties = {}
- properties['read_collections_total_bytes'] = usage[UNWEIGHTED_READ_SIZE_COL]
- properties['read_collections_weighted_bytes'] = (
- usage[WEIGHTED_READ_SIZE_COL])
- properties['persisted_collections_total_bytes'] = (
- usage[UNWEIGHTED_PERSIST_SIZE_COL])
- properties['persisted_collections_weighted_bytes'] = (
- usage[WEIGHTED_PERSIST_SIZE_COL])
- body['properties'] = properties
- # TODO(misha): Confirm that this will throw an exception if it
- # fails to create the log entry.
- arv.logs().create(body=body).execute()
-
-def getKeepServers():
- response = arv.keep_disks().list().execute()
- return [[keep_server['service_host'], keep_server['service_port']]
- for keep_server in response['items']]
-
-
-def getKeepBlocks(keep_servers):
- blocks = []
- for host,port in keep_servers:
- response = urllib2.urlopen('http://%s:%d/index' % (host, port))
- server_blocks = [line.split(' ')
- for line in response.read().split('\n')
- if line]
- server_blocks = [(block_id, int(mtime))
- for block_id, mtime in server_blocks]
- blocks.append(server_blocks)
- return blocks
-
-def getKeepStats(keep_servers):
- MOUNT_COLUMN = 5
- TOTAL_COLUMN = 1
- FREE_COLUMN = 3
- DISK_BLOCK_SIZE = 1024
- stats = []
- for host,port in keep_servers:
- response = urllib2.urlopen('http://%s:%d/status.json' % (host, port))
-
- parsed_json = json.load(response)
- df_entries = [line.split()
- for line in parsed_json['df'].split('\n')
- if line]
- keep_volumes = [columns
- for columns in df_entries
- if 'keep' in columns[MOUNT_COLUMN]]
- total_space = DISK_BLOCK_SIZE*sum(map(int,map(itemgetter(TOTAL_COLUMN),
- keep_volumes)))
- free_space = DISK_BLOCK_SIZE*sum(map(int,map(itemgetter(FREE_COLUMN),
- keep_volumes)))
- stats.append([total_space, free_space])
- return stats
-
-
-def computeReplication(keep_blocks):
- for server_blocks in keep_blocks:
- for block_uuid, _ in server_blocks:
- block_to_replication[block_uuid] += 1
- log.debug('Seeing the following replication levels among blocks: %s',
- str(set(block_to_replication.values())))
-
-
-def computeGarbageCollectionCandidates():
- for server_blocks in keep_blocks:
- block_to_latest_mtime.addValues(server_blocks)
- empty_set = set()
- garbage_collection_priority = sorted(
- [(block,mtime)
- for block,mtime in block_to_latest_mtime.items()
- if len(block_to_persisters.get(block,empty_set)) == 0],
- key = itemgetter(1))
- global garbage_collection_report
- garbage_collection_report = []
- cumulative_disk_size = 0
- for block,mtime in garbage_collection_priority:
- disk_size = blockDiskUsage(block)
- cumulative_disk_size += disk_size
- garbage_collection_report.append(
- (block,
- mtime,
- disk_size,
- cumulative_disk_size,
- float(free_keep_space + cumulative_disk_size)/total_keep_space))
-
- print 'The oldest Garbage Collection Candidates: '
- pprint.pprint(garbage_collection_report[:20])
-
-
-def outputGarbageCollectionReport(filename):
- with open(filename, 'wb') as csvfile:
- gcwriter = csv.writer(csvfile)
- gcwriter.writerow(['block uuid', 'latest mtime', 'disk size',
- 'cumulative size', 'disk free'])
- for line in garbage_collection_report:
- gcwriter.writerow(line)
-
-def computeGarbageCollectionHistogram():
- # TODO(misha): Modify this to allow users to specify the number of
- # histogram buckets through a flag.
- histogram = []
- last_percentage = -1
- for _,mtime,_,_,disk_free in garbage_collection_report:
- curr_percentage = percentageFloor(disk_free)
- if curr_percentage > last_percentage:
- histogram.append( (mtime, curr_percentage) )
- last_percentage = curr_percentage
-
- log.info('Garbage collection histogram is: %s', histogram)
-
- return histogram
-
-
-def logGarbageCollectionHistogram():
- body = {}
- # TODO(misha): Decide whether we should specify an object_uuid in
- # the body and if so, which uuid to use.
- body['event_type'] = args.block_age_free_space_histogram_log_event_type
- properties = {}
- properties['histogram'] = garbage_collection_histogram
- body['properties'] = properties
- # TODO(misha): Confirm that this will throw an exception if it
- # fails to create the log entry.
- arv.logs().create(body=body).execute()
-
-
-def detectReplicationProblems():
- blocks_not_in_any_collections.update(
- set(block_to_replication.keys()).difference(block_to_collections.keys()))
- underreplicated_persisted_blocks.update(
- [uuid
- for uuid, persister_replication in block_to_persister_replication.items()
- if len(persister_replication) > 0 and
- block_to_replication[uuid] < max(persister_replication.values())])
- overreplicated_persisted_blocks.update(
- [uuid
- for uuid, persister_replication in block_to_persister_replication.items()
- if len(persister_replication) > 0 and
- block_to_replication[uuid] > max(persister_replication.values())])
-
- log.info('Found %d blocks not in any collections, e.g. %s...',
- len(blocks_not_in_any_collections),
- ','.join(list(blocks_not_in_any_collections)[:5]))
- log.info('Found %d underreplicated blocks, e.g. %s...',
- len(underreplicated_persisted_blocks),
- ','.join(list(underreplicated_persisted_blocks)[:5]))
- log.info('Found %d overreplicated blocks, e.g. %s...',
- len(overreplicated_persisted_blocks),
- ','.join(list(overreplicated_persisted_blocks)[:5]))
-
- # TODO:
- # Read blocks sorted by mtime
- # Cache window vs % free space
- # Collections which candidates will appear in
- # Youngest underreplicated read blocks that appear in collections.
- # Report Collections that have blocks which are missing from (or
- # underreplicated in) keep.
-
-
-# This is the main flow here
-
-parser = argparse.ArgumentParser(description='Report on keep disks.')
-"""The command line argument parser we use.
-
-We only use it in the __main__ block, but leave it outside the block
-in case another package wants to use it or customize it by specifying
-it as a parent to their commandline parser.
-"""
-parser.add_argument('-m',
- '--max-api-results',
- type=int,
- default=5000,
- help=('The max results to get at once.'))
-parser.add_argument('-p',
- '--port',
- type=int,
- default=9090,
- help=('The port number to serve on. 0 means no server.'))
-parser.add_argument('-v',
- '--verbose',
- help='increase output verbosity',
- action='store_true')
-parser.add_argument('-u',
- '--uuid',
- help='uuid of specific collection to process')
-parser.add_argument('--require-admin-user',
- action='store_true',
- default=True,
- help='Fail if the user is not an admin [default]')
-parser.add_argument('--no-require-admin-user',
- dest='require_admin_user',
- action='store_false',
- help=('Allow users without admin permissions with '
- 'only a warning.'))
-parser.add_argument('--log-to-workbench',
- action='store_true',
- default=False,
- help='Log findings to workbench')
-parser.add_argument('--no-log-to-workbench',
- dest='log_to_workbench',
- action='store_false',
- help='Don\'t log findings to workbench [default]')
-parser.add_argument('--user-storage-log-event-type',
- default='user-storage-report',
- help=('The event type to set when logging user '
- 'storage usage to workbench.'))
-parser.add_argument('--block-age-free-space-histogram-log-event-type',
- default='block-age-free-space-histogram',
- help=('The event type to set when logging user '
- 'storage usage to workbench.'))
-parser.add_argument('--garbage-collection-file',
- default='',
- help=('The file to write a garbage collection report, or '
- 'leave empty for no report.'))
-
-args = None
-
-# TODO(misha): Think about moving some of this to the __main__ block.
-log = logging.getLogger('arvados.services.datamanager')
-stderr_handler = logging.StreamHandler()
-log.setLevel(logging.INFO)
-stderr_handler.setFormatter(
- logging.Formatter('%(asctime)-15s %(levelname)-8s %(message)s'))
-log.addHandler(stderr_handler)
-
-# Global Data - don't try this at home
-collection_uuids = []
-
-# These maps all map from uuids to a set of uuids
-block_to_collections = defaultdict(set) # keep blocks
-reader_to_collections = defaultdict(set) # collection(s) for which the user has read access
-persister_to_collections = defaultdict(set) # collection(s) which the user has persisted
-block_to_readers = defaultdict(set)
-block_to_persisters = defaultdict(set)
-block_to_persister_replication = defaultdict(maxdict)
-reader_to_blocks = defaultdict(set)
-persister_to_blocks = defaultdict(set)
-
-UNWEIGHTED_READ_SIZE_COL = 0
-WEIGHTED_READ_SIZE_COL = 1
-UNWEIGHTED_PERSIST_SIZE_COL = 2
-WEIGHTED_PERSIST_SIZE_COL = 3
-NUM_COLS = 4
-user_to_usage = defaultdict(lambda : [0,]*NUM_COLS)
-
-keep_servers = []
-keep_blocks = []
-keep_stats = []
-total_keep_space = 0
-free_keep_space = 0
-
-block_to_replication = defaultdict(lambda: 0)
-block_to_latest_mtime = maxdict()
-
-garbage_collection_report = []
-"""A list of non-persisted blocks, sorted by increasing mtime
-
-Each entry is of the form (block uuid, latest mtime, disk size,
-cumulative size)
-
-* block uuid: The id of the block we want to delete
-* latest mtime: The latest mtime of the block across all keep servers.
-* disk size: The total disk space used by this block (block size
-multiplied by current replication level)
-* cumulative disk size: The sum of this block's disk size and all the
-blocks listed above it
-* disk free: The proportion of our disk space that would be free if we
-deleted this block and all the above. So this is (free disk space +
-cumulative disk size) / total disk capacity
-"""
-
-garbage_collection_histogram = []
-""" Shows the tradeoff of keep block age vs keep disk free space.
-
-Each entry is of the form (mtime, Disk Proportion).
-
-An entry of the form (1388747781, 0.52) means that if we deleted the
-oldest non-presisted blocks until we had 52% of the disk free, then
-all blocks with an mtime greater than 1388747781 would be preserved.
-"""
-
-# Stuff to report on
-blocks_not_in_any_collections = set()
-underreplicated_persisted_blocks = set()
-overreplicated_persisted_blocks = set()
-
-all_data_loaded = False
-
-def loadAllData():
- checkUserIsAdmin()
-
- log.info('Building Collection List')
- global collection_uuids
- collection_uuids = filter(None, [extractUuid(candidate)
- for candidate in buildCollectionsList()])
-
- log.info('Reading Collections')
- readCollections(collection_uuids)
-
- if args.verbose:
- pprint.pprint(CollectionInfo.all_by_uuid)
-
- log.info('Reading Links')
- readLinks()
-
- reportMostPopularCollections()
-
- log.info('Building Maps')
- buildMaps()
-
- reportBusiestUsers()
-
- log.info('Getting Keep Servers')
- global keep_servers
- keep_servers = getKeepServers()
-
- print keep_servers
-
- log.info('Getting Blocks from each Keep Server.')
- global keep_blocks
- keep_blocks = getKeepBlocks(keep_servers)
-
- log.info('Getting Stats from each Keep Server.')
- global keep_stats, total_keep_space, free_keep_space
- keep_stats = getKeepStats(keep_servers)
-
- total_keep_space = sum(map(itemgetter(0), keep_stats))
- free_keep_space = sum(map(itemgetter(1), keep_stats))
-
- # TODO(misha): Delete this hack when the keep servers are fixed!
- # This hack deals with the fact that keep servers report each other's disks.
- total_keep_space /= len(keep_stats)
- free_keep_space /= len(keep_stats)
-
- log.info('Total disk space: %s, Free disk space: %s (%d%%).' %
- (fileSizeFormat(total_keep_space),
- fileSizeFormat(free_keep_space),
- 100*free_keep_space/total_keep_space))
-
- computeReplication(keep_blocks)
-
- log.info('average replication level is %f',
- (float(sum(block_to_replication.values())) /
- len(block_to_replication)))
-
- computeGarbageCollectionCandidates()
-
- if args.garbage_collection_file:
- log.info('Writing garbage Collection report to %s',
- args.garbage_collection_file)
- outputGarbageCollectionReport(args.garbage_collection_file)
-
- global garbage_collection_histogram
- garbage_collection_histogram = computeGarbageCollectionHistogram()
-
- if args.log_to_workbench:
- logGarbageCollectionHistogram()
-
- detectReplicationProblems()
-
- computeUserStorageUsage()
- printUserStorageUsage()
- if args.log_to_workbench:
- logUserStorageUsage()
-
- global all_data_loaded
- all_data_loaded = True
-
-
-class DataManagerHandler(BaseHTTPRequestHandler):
- USER_PATH = 'user'
- COLLECTION_PATH = 'collection'
- BLOCK_PATH = 'block'
-
- def userLink(self, uuid):
- return ('<A HREF="/%(path)s/%(uuid)s">%(uuid)s</A>' %
- {'uuid': uuid,
- 'path': DataManagerHandler.USER_PATH})
-
- def collectionLink(self, uuid):
- return ('<A HREF="/%(path)s/%(uuid)s">%(uuid)s</A>' %
- {'uuid': uuid,
- 'path': DataManagerHandler.COLLECTION_PATH})
-
- def blockLink(self, uuid):
- return ('<A HREF="/%(path)s/%(uuid)s">%(uuid)s</A>' %
- {'uuid': uuid,
- 'path': DataManagerHandler.BLOCK_PATH})
-
- def writeTop(self, title):
- self.wfile.write('<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n<BODY>' % title)
-
- def writeBottom(self):
- self.wfile.write('</BODY></HTML>\n')
-
- def writeHomePage(self):
- self.send_response(200)
- self.end_headers()
- self.writeTop('Home')
- self.wfile.write('<TABLE>')
- self.wfile.write('<TR><TH>user'
- '<TH>unweighted readable block size'
- '<TH>weighted readable block size'
- '<TH>unweighted persisted block size'
- '<TH>weighted persisted block size</TR>\n')
- for user, usage in user_to_usage.items():
- self.wfile.write('<TR><TD>%s<TD>%s<TD>%s<TD>%s<TD>%s</TR>\n' %
- (self.userLink(user),
- fileSizeFormat(usage[UNWEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[UNWEIGHTED_PERSIST_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_PERSIST_SIZE_COL])))
- self.wfile.write('</TABLE>\n')
- self.writeBottom()
-
- def userExists(self, uuid):
- # Currently this will return false for a user who exists but
- # doesn't appear on any manifests.
- # TODO(misha): Figure out if we need to fix this.
- return user_to_usage.has_key(uuid)
-
- def writeUserPage(self, uuid):
- if not self.userExists(uuid):
- self.send_error(404,
- 'User (%s) Not Found.' % cgi.escape(uuid, quote=False))
- else:
- # Here we assume that since a user exists, they don't need to be
- # html escaped.
- self.send_response(200)
- self.end_headers()
- self.writeTop('User %s' % uuid)
- self.wfile.write('<TABLE>')
- self.wfile.write('<TR><TH>user'
- '<TH>unweighted readable block size'
- '<TH>weighted readable block size'
- '<TH>unweighted persisted block size'
- '<TH>weighted persisted block size</TR>\n')
- usage = user_to_usage[uuid]
- self.wfile.write('<TR><TD>%s<TD>%s<TD>%s<TD>%s<TD>%s</TR>\n' %
- (self.userLink(uuid),
- fileSizeFormat(usage[UNWEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_READ_SIZE_COL]),
- fileSizeFormat(usage[UNWEIGHTED_PERSIST_SIZE_COL]),
- fileSizeFormat(usage[WEIGHTED_PERSIST_SIZE_COL])))
- self.wfile.write('</TABLE>\n')
- self.wfile.write('<P>Persisting Collections: %s\n' %
- ', '.join(map(self.collectionLink,
- persister_to_collections[uuid])))
- self.wfile.write('<P>Reading Collections: %s\n' %
- ', '.join(map(self.collectionLink,
- reader_to_collections[uuid])))
- self.writeBottom()
-
- def collectionExists(self, uuid):
- return CollectionInfo.all_by_uuid.has_key(uuid)
-
- def writeCollectionPage(self, uuid):
- if not self.collectionExists(uuid):
- self.send_error(404,
- 'Collection (%s) Not Found.' % cgi.escape(uuid, quote=False))
- else:
- collection = CollectionInfo.get(uuid)
- # Here we assume that since a collection exists, its id doesn't
- # need to be html escaped.
- self.send_response(200)
- self.end_headers()
- self.writeTop('Collection %s' % uuid)
- self.wfile.write('<H1>Collection %s</H1>\n' % uuid)
- self.wfile.write('<P>Total size %s (not factoring in replication).\n' %
- fileSizeFormat(collection.byteSize()))
- self.wfile.write('<P>Readers: %s\n' %
- ', '.join(map(self.userLink, collection.reader_uuids)))
-
- if len(collection.persister_replication) == 0:
- self.wfile.write('<P>No persisters\n')
- else:
- replication_to_users = defaultdict(set)
- for user,replication in collection.persister_replication.items():
- replication_to_users[replication].add(user)
- replication_levels = sorted(replication_to_users.keys())
-
- self.wfile.write('<P>%d persisters in %d replication level(s) maxing '
- 'out at %dx replication:\n' %
- (len(collection.persister_replication),
- len(replication_levels),
- replication_levels[-1]))
-
- # TODO(misha): This code is used twice, let's move it to a method.
- self.wfile.write('<TABLE><TR><TH>%s</TR>\n' %
- '<TH>'.join(['Replication Level ' + str(x)
- for x in replication_levels]))
- self.wfile.write('<TR>\n')
- for replication_level in replication_levels:
- users = replication_to_users[replication_level]
- self.wfile.write('<TD valign="top">%s\n' % '<BR>\n'.join(
- map(self.userLink, users)))
- self.wfile.write('</TR></TABLE>\n')
-
- replication_to_blocks = defaultdict(set)
- for block in collection.block_uuids:
- replication_to_blocks[block_to_replication[block]].add(block)
- replication_levels = sorted(replication_to_blocks.keys())
- self.wfile.write('<P>%d blocks in %d replication level(s):\n' %
- (len(collection.block_uuids), len(replication_levels)))
- self.wfile.write('<TABLE><TR><TH>%s</TR>\n' %
- '<TH>'.join(['Replication Level ' + str(x)
- for x in replication_levels]))
- self.wfile.write('<TR>\n')
- for replication_level in replication_levels:
- blocks = replication_to_blocks[replication_level]
- self.wfile.write('<TD valign="top">%s\n' % '<BR>\n'.join(blocks))
- self.wfile.write('</TR></TABLE>\n')
-
-
- def do_GET(self):
- if not all_data_loaded:
- self.send_error(503,
- 'Sorry, but I am still loading all the data I need.')
- else:
- # Removing leading '/' and process request path
- split_path = self.path[1:].split('/')
- request_type = split_path[0]
- log.debug('path (%s) split as %s with request_type %s' % (self.path,
- split_path,
- request_type))
- if request_type == '':
- self.writeHomePage()
- elif request_type == DataManagerHandler.USER_PATH:
- self.writeUserPage(split_path[1])
- elif request_type == DataManagerHandler.COLLECTION_PATH:
- self.writeCollectionPage(split_path[1])
- else:
- self.send_error(404, 'Unrecognized request path.')
- return
-
-class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
- """Handle requests in a separate thread."""
-
-
-if __name__ == '__main__':
- args = parser.parse_args()
-
- if args.port == 0:
- loadAllData()
- else:
- loader = threading.Thread(target = loadAllData, name = 'loader')
- loader.start()
-
- server = ThreadedHTTPServer(('localhost', args.port), DataManagerHandler)
- server.serve_forever()
+++ /dev/null
-#! /usr/bin/env python
-
-import datamanager
-import unittest
-
-class TestComputeWeightedReplicationCosts(unittest.TestCase):
- def test_obvious(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,]),
- {1:1.0})
-
- def test_simple(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([2,]),
- {2:2.0})
-
- def test_even_split(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,1]),
- {1:0.5})
-
- def test_even_split_bigger(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([2,2]),
- {2:1.0})
-
- def test_uneven_split(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,2]),
- {1:0.5, 2:1.5})
-
- def test_uneven_split_bigger(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,3]),
- {1:0.5, 3:2.5})
-
- def test_uneven_split_jumble(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,3,6,6,10]),
- {1:0.2, 3:0.7, 6:1.7, 10:5.7})
-
- def test_documentation_example(self):
- self.assertEqual(datamanager.computeWeightedReplicationCosts([1,1,3,6,6]),
- {1:0.2, 3: 0.2 + 2.0 / 3, 6: 0.2 + 2.0 / 3 + 1.5})
-
-
-if __name__ == '__main__':
- unittest.main()
+++ /dev/null
-/* Deals with getting Keep Server blocks from API Server and Keep Servers. */
-
-package keep
-
-import (
- "bufio"
- "encoding/json"
- "errors"
- "flag"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "io"
- "io/ioutil"
- "log"
- "net/http"
- "strconv"
- "strings"
- "time"
-)
-
-// ServerAddress struct
-type ServerAddress struct {
- SSL bool `json:"service_ssl_flag"`
- Host string `json:"service_host"`
- Port int `json:"service_port"`
- UUID string `json:"uuid"`
- ServiceType string `json:"service_type"`
-}
-
-// BlockInfo is info about a particular block returned by the server
-type BlockInfo struct {
- Digest blockdigest.DigestWithSize
- Mtime int64 // TODO(misha): Replace this with a timestamp.
-}
-
-// BlockServerInfo is info about a specified block given by a server
-type BlockServerInfo struct {
- ServerIndex int
- Mtime int64 // TODO(misha): Replace this with a timestamp.
-}
-
-// ServerContents struct
-type ServerContents struct {
- BlockDigestToInfo map[blockdigest.DigestWithSize]BlockInfo
-}
-
-// ServerResponse struct
-type ServerResponse struct {
- Address ServerAddress
- Contents ServerContents
- Err error
-}
-
-// ReadServers struct
-type ReadServers struct {
- ReadAllServers bool
- KeepServerIndexToAddress []ServerAddress
- KeepServerAddressToIndex map[ServerAddress]int
- ServerToContents map[ServerAddress]ServerContents
- BlockToServers map[blockdigest.DigestWithSize][]BlockServerInfo
- BlockReplicationCounts map[int]int
-}
-
-// GetKeepServersParams struct
-type GetKeepServersParams struct {
- Client *arvadosclient.ArvadosClient
- Logger *logger.Logger
- Limit int
-}
-
-// ServiceList consists of the addresses of all the available kee servers
-type ServiceList struct {
- ItemsAvailable int `json:"items_available"`
- KeepServers []ServerAddress `json:"items"`
-}
-
-var serviceType string
-
-func init() {
- flag.StringVar(&serviceType,
- "service-type",
- "disk",
- "Operate only on keep_services with the specified service_type, ignoring all others.")
-}
-
-// String
-// TODO(misha): Change this to include the UUID as well.
-func (s ServerAddress) String() string {
- return s.URL()
-}
-
-// URL of the keep server
-func (s ServerAddress) URL() string {
- if s.SSL {
- return fmt.Sprintf("https://%s:%d", s.Host, s.Port)
- }
- return fmt.Sprintf("http://%s:%d", s.Host, s.Port)
-}
-
-// GetKeepServersAndSummarize gets keep servers from api
-func GetKeepServersAndSummarize(params GetKeepServersParams) (results ReadServers, err error) {
- results, err = GetKeepServers(params)
- if err != nil {
- return
- }
- log.Printf("Returned %d keep disks", len(results.ServerToContents))
-
- results.Summarize(params.Logger)
- log.Printf("Replication level distribution: %v",
- results.BlockReplicationCounts)
-
- return
-}
-
-// GetKeepServers from api server
-func GetKeepServers(params GetKeepServersParams) (results ReadServers, err error) {
- sdkParams := arvadosclient.Dict{
- "filters": [][]string{{"service_type", "!=", "proxy"}},
- }
- if params.Limit > 0 {
- sdkParams["limit"] = params.Limit
- }
-
- var sdkResponse ServiceList
- err = params.Client.List("keep_services", sdkParams, &sdkResponse)
-
- if err != nil {
- return
- }
-
- var keepServers []ServerAddress
- for _, server := range sdkResponse.KeepServers {
- if server.ServiceType == serviceType {
- keepServers = append(keepServers, server)
- } else {
- log.Printf("Skipping keep_service %q because its service_type %q does not match -service-type=%q", server, server.ServiceType, serviceType)
- }
- }
-
- if len(keepServers) == 0 {
- return results, fmt.Errorf("Found no keepservices with the service type %v", serviceType)
- }
-
- if params.Logger != nil {
- params.Logger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- keepInfo["num_keep_servers_available"] = sdkResponse.ItemsAvailable
- keepInfo["num_keep_servers_received"] = len(sdkResponse.KeepServers)
- keepInfo["keep_servers"] = sdkResponse.KeepServers
- keepInfo["indexable_keep_servers"] = keepServers
- })
- }
-
- log.Printf("Received keep services list: %+v", sdkResponse)
-
- if len(sdkResponse.KeepServers) < sdkResponse.ItemsAvailable {
- return results, fmt.Errorf("Did not receive all available keep servers: %+v", sdkResponse)
- }
-
- results.KeepServerIndexToAddress = keepServers
- results.KeepServerAddressToIndex = make(map[ServerAddress]int)
- for i, address := range results.KeepServerIndexToAddress {
- results.KeepServerAddressToIndex[address] = i
- }
-
- log.Printf("Got Server Addresses: %v", results)
-
- // Send off all the index requests concurrently
- responseChan := make(chan ServerResponse)
- for _, keepServer := range results.KeepServerIndexToAddress {
- // The above keepsServer variable is reused for each iteration, so
- // it would be shared across all goroutines. This would result in
- // us querying one server n times instead of n different servers
- // as we intended. To avoid this we add it as an explicit
- // parameter which gets copied. This bug and solution is described
- // in https://golang.org/doc/effective_go.html#channels
- go func(keepServer ServerAddress) {
- responseChan <- GetServerContents(params.Logger,
- keepServer,
- params.Client)
- }(keepServer)
- }
-
- results.ServerToContents = make(map[ServerAddress]ServerContents)
- results.BlockToServers = make(map[blockdigest.DigestWithSize][]BlockServerInfo)
-
- // Read all the responses
- for i := range results.KeepServerIndexToAddress {
- _ = i // Here to prevent go from complaining.
- response := <-responseChan
-
- // Check if there were any errors during GetServerContents
- if response.Err != nil {
- return results, response.Err
- }
-
- log.Printf("Received channel response from %v containing %d files",
- response.Address,
- len(response.Contents.BlockDigestToInfo))
- results.ServerToContents[response.Address] = response.Contents
- serverIndex := results.KeepServerAddressToIndex[response.Address]
- for _, blockInfo := range response.Contents.BlockDigestToInfo {
- results.BlockToServers[blockInfo.Digest] = append(
- results.BlockToServers[blockInfo.Digest],
- BlockServerInfo{ServerIndex: serverIndex,
- Mtime: blockInfo.Mtime})
- }
- }
- return
-}
-
-// GetServerContents of the keep server
-func GetServerContents(arvLogger *logger.Logger,
- keepServer ServerAddress,
- arv *arvadosclient.ArvadosClient) (response ServerResponse) {
-
- err := GetServerStatus(arvLogger, keepServer, arv)
- if err != nil {
- response.Err = err
- return
- }
-
- req, err := CreateIndexRequest(arvLogger, keepServer, arv)
- if err != nil {
- response.Err = err
- return
- }
-
- resp, err := arv.Client.Do(req)
- if err != nil {
- response.Err = err
- return
- }
-
- response, err = ReadServerResponse(arvLogger, keepServer, resp)
- if err != nil {
- response.Err = err
- return
- }
-
- return
-}
-
-// GetServerStatus get keep server status by invoking /status.json
-func GetServerStatus(arvLogger *logger.Logger,
- keepServer ServerAddress,
- arv *arvadosclient.ArvadosClient) error {
- url := fmt.Sprintf("http://%s:%d/status.json",
- keepServer.Host,
- keepServer.Port)
-
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- serverInfo := make(map[string]interface{})
- serverInfo["status_request_sent_at"] = now
- serverInfo["host"] = keepServer.Host
- serverInfo["port"] = keepServer.Port
-
- keepInfo[keepServer.UUID] = serverInfo
- })
- }
-
- resp, err := arv.Client.Get(url)
- if err != nil {
- return fmt.Errorf("Error getting keep status from %s: %v", url, err)
- } else if resp.StatusCode != 200 {
- return fmt.Errorf("Received error code %d in response to request "+
- "for %s status: %s",
- resp.StatusCode, url, resp.Status)
- }
-
- var keepStatus map[string]interface{}
- decoder := json.NewDecoder(resp.Body)
- decoder.UseNumber()
- err = decoder.Decode(&keepStatus)
- if err != nil {
- return fmt.Errorf("Error decoding keep status from %s: %v", url, err)
- }
-
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- serverInfo := keepInfo[keepServer.UUID].(map[string]interface{})
- serverInfo["status_response_processed_at"] = now
- serverInfo["status"] = keepStatus
- })
- }
-
- return nil
-}
-
-// CreateIndexRequest to the keep server
-func CreateIndexRequest(arvLogger *logger.Logger,
- keepServer ServerAddress,
- arv *arvadosclient.ArvadosClient) (req *http.Request, err error) {
- url := fmt.Sprintf("http://%s:%d/index", keepServer.Host, keepServer.Port)
- log.Println("About to fetch keep server contents from " + url)
-
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- serverInfo := keepInfo[keepServer.UUID].(map[string]interface{})
- serverInfo["index_request_sent_at"] = now
- })
- }
-
- req, err = http.NewRequest("GET", url, nil)
- if err != nil {
- return req, fmt.Errorf("Error building http request for %s: %v", url, err)
- }
-
- req.Header.Add("Authorization", "OAuth2 "+arv.ApiToken)
- return req, err
-}
-
-// ReadServerResponse reads reasponse from keep server
-func ReadServerResponse(arvLogger *logger.Logger,
- keepServer ServerAddress,
- resp *http.Response) (response ServerResponse, err error) {
-
- if resp.StatusCode != 200 {
- return response, fmt.Errorf("Received error code %d in response to index request for %s: %s",
- resp.StatusCode, keepServer.String(), resp.Status)
- }
-
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- serverInfo := keepInfo[keepServer.UUID].(map[string]interface{})
- serverInfo["index_response_received_at"] = now
- })
- }
-
- response.Address = keepServer
- response.Contents.BlockDigestToInfo =
- make(map[blockdigest.DigestWithSize]BlockInfo)
- reader := bufio.NewReader(resp.Body)
- numLines, numDuplicates, numSizeDisagreements := 0, 0, 0
- for {
- numLines++
- line, err := reader.ReadString('\n')
- if err == io.EOF {
- return response, fmt.Errorf("Index from %s truncated at line %d",
- keepServer.String(), numLines)
- } else if err != nil {
- return response, fmt.Errorf("Error reading index response from %s at line %d: %v",
- keepServer.String(), numLines, err)
- }
- if line == "\n" {
- if _, err := reader.Peek(1); err == nil {
- extra, _ := reader.ReadString('\n')
- return response, fmt.Errorf("Index from %s had trailing data at line %d after EOF marker: %s",
- keepServer.String(), numLines+1, extra)
- } else if err != io.EOF {
- return response, fmt.Errorf("Index from %s had read error after EOF marker at line %d: %v",
- keepServer.String(), numLines, err)
- }
- numLines--
- break
- }
- blockInfo, err := parseBlockInfoFromIndexLine(line)
- if err != nil {
- return response, fmt.Errorf("Error parsing BlockInfo from index line "+
- "received from %s: %v",
- keepServer.String(),
- err)
- }
-
- if storedBlock, ok := response.Contents.BlockDigestToInfo[blockInfo.Digest]; ok {
- // This server returned multiple lines containing the same block digest.
- numDuplicates++
- // Keep the block that's newer.
- if storedBlock.Mtime < blockInfo.Mtime {
- response.Contents.BlockDigestToInfo[blockInfo.Digest] = blockInfo
- }
- } else {
- response.Contents.BlockDigestToInfo[blockInfo.Digest] = blockInfo
- }
- }
-
- log.Printf("%s index contained %d lines with %d duplicates with "+
- "%d size disagreements",
- keepServer.String(),
- numLines,
- numDuplicates,
- numSizeDisagreements)
-
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- serverInfo := keepInfo[keepServer.UUID].(map[string]interface{})
-
- serverInfo["processing_finished_at"] = now
- serverInfo["lines_received"] = numLines
- serverInfo["duplicates_seen"] = numDuplicates
- serverInfo["size_disagreements_seen"] = numSizeDisagreements
- })
- }
- resp.Body.Close()
- return
-}
-
-func parseBlockInfoFromIndexLine(indexLine string) (blockInfo BlockInfo, err error) {
- tokens := strings.Fields(indexLine)
- if len(tokens) != 2 {
- err = fmt.Errorf("Expected 2 tokens per line but received a "+
- "line containing %#q instead.",
- tokens)
- }
-
- var locator blockdigest.BlockLocator
- if locator, err = blockdigest.ParseBlockLocator(tokens[0]); err != nil {
- err = fmt.Errorf("%v Received error while parsing line \"%#q\"",
- err, indexLine)
- return
- }
- if len(locator.Hints) > 0 {
- err = fmt.Errorf("Block locator in index line should not contain hints "+
- "but it does: %#q",
- locator)
- return
- }
-
- var ns int64
- ns, err = strconv.ParseInt(tokens[1], 10, 64)
- if err != nil {
- return
- }
- if ns < 1e12 {
- // An old version of keepstore is giving us timestamps
- // in seconds instead of nanoseconds. (This threshold
- // correctly handles all times between 1970-01-02 and
- // 33658-09-27.)
- ns = ns * 1e9
- }
- blockInfo.Mtime = ns
- blockInfo.Digest = blockdigest.DigestWithSize{
- Digest: locator.Digest,
- Size: uint32(locator.Size),
- }
- return
-}
-
-// Summarize results from keep server
-func (readServers *ReadServers) Summarize(arvLogger *logger.Logger) {
- readServers.BlockReplicationCounts = make(map[int]int)
- for _, infos := range readServers.BlockToServers {
- replication := len(infos)
- readServers.BlockReplicationCounts[replication]++
- }
-
- if arvLogger != nil {
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- keepInfo := logger.GetOrCreateMap(p, "keep_info")
- keepInfo["distinct_blocks_stored"] = len(readServers.BlockToServers)
- })
- }
-}
-
-// TrashRequest struct
-type TrashRequest struct {
- Locator string `json:"locator"`
- BlockMtime int64 `json:"block_mtime"`
-}
-
-// TrashList is an array of TrashRequest objects
-type TrashList []TrashRequest
-
-// SendTrashLists to trash queue
-func SendTrashLists(arvLogger *logger.Logger, kc *keepclient.KeepClient, spl map[string]TrashList, dryRun bool) (errs []error) {
- count := 0
- barrier := make(chan error)
-
- client := kc.Client
-
- for url, v := range spl {
- if arvLogger != nil {
- // We need a local variable because Update doesn't call our mutator func until later,
- // when our list variable might have been reused by the next loop iteration.
- url := url
- trashLen := len(v)
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- trashListInfo := logger.GetOrCreateMap(p, "trash_list_len")
- trashListInfo[url] = trashLen
- })
- }
-
- if dryRun {
- log.Printf("dry run, not sending trash list to service %s with %d blocks", url, len(v))
- continue
- }
-
- count++
- log.Printf("Sending trash list to %v", url)
-
- go (func(url string, v TrashList) {
- pipeReader, pipeWriter := io.Pipe()
- go (func() {
- enc := json.NewEncoder(pipeWriter)
- enc.Encode(v)
- pipeWriter.Close()
- })()
-
- req, err := http.NewRequest("PUT", fmt.Sprintf("%s/trash", url), pipeReader)
- if err != nil {
- log.Printf("Error creating trash list request for %v error: %v", url, err.Error())
- barrier <- err
- return
- }
-
- req.Header.Add("Authorization", "OAuth2 "+kc.Arvados.ApiToken)
-
- // Make the request
- var resp *http.Response
- if resp, err = client.Do(req); err != nil {
- log.Printf("Error sending trash list to %v error: %v", url, err.Error())
- barrier <- err
- return
- }
-
- log.Printf("Sent trash list to %v: response was HTTP %v", url, resp.Status)
-
- io.Copy(ioutil.Discard, resp.Body)
- resp.Body.Close()
-
- if resp.StatusCode != 200 {
- barrier <- errors.New(fmt.Sprintf("Got HTTP code %v", resp.StatusCode))
- } else {
- barrier <- nil
- }
- })(url, v)
- }
-
- for i := 0; i < count; i++ {
- b := <-barrier
- if b != nil {
- errs = append(errs, b)
- }
- }
-
- return errs
-}
+++ /dev/null
-package keep
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "net/http"
- "net/http/httptest"
- "net/url"
- "strconv"
- "strings"
- "testing"
-
- "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
- "git.curoverse.com/arvados.git/sdk/go/arvadostest"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
-
- . "gopkg.in/check.v1"
-)
-
-// Gocheck boilerplate
-func Test(t *testing.T) {
- TestingT(t)
-}
-
-type KeepSuite struct{}
-
-var _ = Suite(&KeepSuite{})
-
-type TestHandler struct {
- request TrashList
-}
-
-func (ts *TestHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
- r := json.NewDecoder(req.Body)
- r.Decode(&ts.request)
-}
-
-func (s *KeepSuite) TestSendTrashLists(c *C) {
- th := TestHandler{}
- server := httptest.NewServer(&th)
- defer server.Close()
-
- tl := map[string]TrashList{
- server.URL: {TrashRequest{"000000000000000000000000deadbeef", 99}}}
-
- arv := &arvadosclient.ArvadosClient{ApiToken: "abc123"}
- kc := keepclient.KeepClient{Arvados: arv, Client: &http.Client{}}
- kc.SetServiceRoots(map[string]string{"xxxx": server.URL},
- map[string]string{"xxxx": server.URL},
- map[string]string{})
-
- err := SendTrashLists(nil, &kc, tl, false)
-
- c.Check(err, IsNil)
-
- c.Check(th.request,
- DeepEquals,
- tl[server.URL])
-
-}
-
-type TestHandlerError struct {
-}
-
-func (tse *TestHandlerError) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
- http.Error(writer, "I'm a teapot", 418)
-}
-
-func sendTrashListError(c *C, server *httptest.Server) {
- tl := map[string]TrashList{
- server.URL: {TrashRequest{"000000000000000000000000deadbeef", 99}}}
-
- arv := &arvadosclient.ArvadosClient{ApiToken: "abc123"}
- kc := keepclient.KeepClient{Arvados: arv, Client: &http.Client{}}
- kc.SetServiceRoots(map[string]string{"xxxx": server.URL},
- map[string]string{"xxxx": server.URL},
- map[string]string{})
-
- err := SendTrashLists(nil, &kc, tl, false)
-
- c.Check(err, NotNil)
- c.Check(err[0], NotNil)
-}
-
-func (s *KeepSuite) TestSendTrashListErrorResponse(c *C) {
- server := httptest.NewServer(&TestHandlerError{})
- sendTrashListError(c, server)
- defer server.Close()
-}
-
-func (s *KeepSuite) TestSendTrashListUnreachable(c *C) {
- sendTrashListError(c, httptest.NewUnstartedServer(&TestHandler{}))
-}
-
-type APITestData struct {
- numServers int
- serverType string
- statusCode int
-}
-
-func (s *KeepSuite) TestGetKeepServers_UnsupportedServiceType(c *C) {
- testGetKeepServersFromAPI(c, APITestData{1, "notadisk", 200}, "Found no keepservices with the service type disk")
-}
-
-func (s *KeepSuite) TestGetKeepServers_ReceivedTooFewServers(c *C) {
- testGetKeepServersFromAPI(c, APITestData{2, "disk", 200}, "Did not receive all available keep servers")
-}
-
-func (s *KeepSuite) TestGetKeepServers_ServerError(c *C) {
- testGetKeepServersFromAPI(c, APITestData{-1, "disk", -1}, "arvados API server error")
-}
-
-func testGetKeepServersFromAPI(c *C, testData APITestData, expectedError string) {
- keepServers := ServiceList{
- ItemsAvailable: testData.numServers,
- KeepServers: []ServerAddress{{
- SSL: false,
- Host: "example.com",
- Port: 12345,
- UUID: "abcdefg",
- ServiceType: testData.serverType,
- }},
- }
-
- ksJSON, _ := json.Marshal(keepServers)
- apiStubResponses := make(map[string]arvadostest.StubResponse)
- apiStubResponses["/arvados/v1/keep_services"] = arvadostest.StubResponse{testData.statusCode, string(ksJSON)}
- apiStub := arvadostest.ServerStub{apiStubResponses}
-
- api := httptest.NewServer(&apiStub)
- defer api.Close()
-
- arv := &arvadosclient.ArvadosClient{
- Scheme: "http",
- ApiServer: api.URL[7:],
- ApiToken: "abc123",
- Client: &http.Client{Transport: &http.Transport{}},
- }
-
- kc := keepclient.KeepClient{Arvados: arv, Client: &http.Client{}}
- kc.SetServiceRoots(map[string]string{"xxxx": "http://example.com:23456"},
- map[string]string{"xxxx": "http://example.com:23456"},
- map[string]string{})
-
- params := GetKeepServersParams{
- Client: arv,
- Logger: nil,
- Limit: 10,
- }
-
- _, err := GetKeepServersAndSummarize(params)
- c.Assert(err, NotNil)
- c.Assert(err, ErrorMatches, fmt.Sprintf(".*%s.*", expectedError))
-}
-
-type KeepServerTestData struct {
- // handle /status.json
- statusStatusCode int
-
- // handle /index
- indexStatusCode int
- indexResponseBody string
-
- // expected error, if any
- expectedError string
-}
-
-func (s *KeepSuite) TestGetKeepServers_ErrorGettingKeepServerStatus(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{500, 200, "ok",
- ".*http://.* 500 Internal Server Error"})
-}
-
-func (s *KeepSuite) TestGetKeepServers_GettingIndex(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, -1, "notok",
- ".*redirect-loop.*"})
-}
-
-func (s *KeepSuite) TestGetKeepServers_ErrorReadServerResponse(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, 500, "notok",
- ".*http://.* 500 Internal Server Error"})
-}
-
-func (s *KeepSuite) TestGetKeepServers_ReadServerResponseTuncatedAtLineOne(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200,
- "notterminatedwithnewline", "Index from http://.* truncated at line 1"})
-}
-
-func (s *KeepSuite) TestGetKeepServers_InvalidBlockLocatorPattern(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200, "testing\n",
- "Error parsing BlockInfo from index line.*"})
-}
-
-func (s *KeepSuite) TestGetKeepServers_ReadServerResponseEmpty(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200, "\n", ""})
-}
-
-func (s *KeepSuite) TestGetKeepServers_ReadServerResponseWithTwoBlocks(c *C) {
- testGetKeepServersAndSummarize(c, KeepServerTestData{200, 200,
- "51752ba076e461ec9ec1d27400a08548+20 1447526361\na048cc05c02ba1ee43ad071274b9e547+52 1447526362\n\n", ""})
-}
-
-func testGetKeepServersAndSummarize(c *C, testData KeepServerTestData) {
- ksStubResponses := make(map[string]arvadostest.StubResponse)
- ksStubResponses["/status.json"] = arvadostest.StubResponse{testData.statusStatusCode, string(`{}`)}
- ksStubResponses["/index"] = arvadostest.StubResponse{testData.indexStatusCode, testData.indexResponseBody}
- ksStub := arvadostest.ServerStub{ksStubResponses}
- ks := httptest.NewServer(&ksStub)
- defer ks.Close()
-
- ksURL, err := url.Parse(ks.URL)
- c.Check(err, IsNil)
- ksHost, port, err := net.SplitHostPort(ksURL.Host)
- ksPort, err := strconv.Atoi(port)
- c.Check(err, IsNil)
-
- servers_list := ServiceList{
- ItemsAvailable: 1,
- KeepServers: []ServerAddress{{
- SSL: false,
- Host: ksHost,
- Port: ksPort,
- UUID: "abcdefg",
- ServiceType: "disk",
- }},
- }
- ksJSON, _ := json.Marshal(servers_list)
- apiStubResponses := make(map[string]arvadostest.StubResponse)
- apiStubResponses["/arvados/v1/keep_services"] = arvadostest.StubResponse{200, string(ksJSON)}
- apiStub := arvadostest.ServerStub{apiStubResponses}
-
- api := httptest.NewServer(&apiStub)
- defer api.Close()
-
- arv := &arvadosclient.ArvadosClient{
- Scheme: "http",
- ApiServer: api.URL[7:],
- ApiToken: "abc123",
- Client: &http.Client{Transport: &http.Transport{}},
- }
-
- kc := keepclient.KeepClient{Arvados: arv, Client: &http.Client{}}
- kc.SetServiceRoots(map[string]string{"xxxx": ks.URL},
- map[string]string{"xxxx": ks.URL},
- map[string]string{})
-
- params := GetKeepServersParams{
- Client: arv,
- Logger: nil,
- Limit: 10,
- }
-
- // GetKeepServersAndSummarize
- results, err := GetKeepServersAndSummarize(params)
-
- if testData.expectedError == "" {
- c.Assert(err, IsNil)
- c.Assert(results, NotNil)
-
- blockToServers := results.BlockToServers
-
- blockLocators := strings.Split(testData.indexResponseBody, "\n")
- for _, loc := range blockLocators {
- locator := strings.Split(loc, " ")[0]
- if locator != "" {
- blockLocator, err := blockdigest.ParseBlockLocator(locator)
- c.Assert(err, IsNil)
-
- blockDigestWithSize := blockdigest.DigestWithSize{blockLocator.Digest, uint32(blockLocator.Size)}
- blockServerInfo := blockToServers[blockDigestWithSize]
- c.Assert(blockServerInfo[0].Mtime, NotNil)
- }
- }
- } else {
- c.Assert(err, ErrorMatches, testData.expectedError)
- }
-}
+++ /dev/null
-/* Datamanager-specific logging methods. */
-
-package loggerutil
-
-import (
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "log"
- "os"
- "runtime"
- "time"
-)
-
-// Useful to call at the beginning of execution to log info about the
-// current run.
-func LogRunInfo(arvLogger *logger.Logger) {
- if arvLogger != nil {
- now := time.Now()
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- runInfo := logger.GetOrCreateMap(p, "run_info")
- runInfo["started_at"] = now
- runInfo["args"] = os.Args
- hostname, err := os.Hostname()
- if err != nil {
- runInfo["hostname_error"] = err.Error()
- } else {
- runInfo["hostname"] = hostname
- }
- runInfo["pid"] = os.Getpid()
- })
- }
-}
-
-// A LogMutator that records the current memory usage. This is most useful as a logger write hook.
-func LogMemoryAlloc(p map[string]interface{}, e map[string]interface{}) {
- runInfo := logger.GetOrCreateMap(p, "run_info")
- var memStats runtime.MemStats
- runtime.ReadMemStats(&memStats)
- runInfo["memory_bytes_in_use"] = memStats.Alloc
- runInfo["memory_bytes_reserved"] = memStats.Sys
-}
-
-func FatalWithMessage(arvLogger *logger.Logger, message string) {
- if arvLogger != nil {
- arvLogger.FinalUpdate(func(p map[string]interface{}, e map[string]interface{}) {
- p["FATAL"] = message
- runInfo := logger.GetOrCreateMap(p, "run_info")
- runInfo["finished_at"] = time.Now()
- })
- }
-
- log.Fatalf(message)
-}
+++ /dev/null
-/* Ensures that we only have one copy of each unique string. This is
-/* not designed for concurrent access. */
-
-package summary
-
-// This code should probably be moved somewhere more universal.
-
-// CanonicalString struct
-type CanonicalString struct {
- m map[string]string
-}
-
-// Get a CanonicalString
-func (cs *CanonicalString) Get(s string) (r string) {
- if cs.m == nil {
- cs.m = make(map[string]string)
- }
- value, found := cs.m[s]
- if found {
- return value
- }
-
- // s may be a substring of a much larger string.
- // If we store s, it will prevent that larger string from getting
- // garbage collected.
- // If this is something you worry about you should change this code
- // to make an explict copy of s using a byte array.
- cs.m[s] = s
- return s
-}
+++ /dev/null
-// Handles writing data to and reading data from disk to speed up development.
-
-package summary
-
-import (
- "encoding/gob"
- "flag"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "git.curoverse.com/arvados.git/services/datamanager/collection"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "log"
- "os"
-)
-
-// Used to locally cache data read from servers to reduce execution
-// time when developing. Not for use in production.
-type serializedData struct {
- ReadCollections collection.ReadCollections
- KeepServerInfo keep.ReadServers
-}
-
-var (
- WriteDataTo string
- readDataFrom string
-)
-
-// DataFetcher to fetch data from keep servers
-type DataFetcher func(arvLogger *logger.Logger,
- readCollections *collection.ReadCollections,
- keepServerInfo *keep.ReadServers) error
-
-func init() {
- flag.StringVar(&WriteDataTo,
- "write-data-to",
- "",
- "Write summary of data received to this file. Used for development only.")
- flag.StringVar(&readDataFrom,
- "read-data-from",
- "",
- "Avoid network i/o and read summary data from this file instead. Used for development only.")
-}
-
-// MaybeWriteData writes data we've read to a file.
-//
-// This is useful for development, so that we don't need to read all
-// our data from the network every time we tweak something.
-//
-// This should not be used outside of development, since you'll be
-// working with stale data.
-func MaybeWriteData(arvLogger *logger.Logger,
- readCollections collection.ReadCollections,
- keepServerInfo keep.ReadServers) error {
- if WriteDataTo == "" {
- return nil
- }
- summaryFile, err := os.Create(WriteDataTo)
- if err != nil {
- return err
- }
- defer summaryFile.Close()
-
- enc := gob.NewEncoder(summaryFile)
- data := serializedData{
- ReadCollections: readCollections,
- KeepServerInfo: keepServerInfo}
- err = enc.Encode(data)
- if err != nil {
- return err
- }
- log.Printf("Wrote summary data to: %s", WriteDataTo)
- return nil
-}
-
-// ShouldReadData should not be used outside of development
-func ShouldReadData() bool {
- return readDataFrom != ""
-}
-
-// ReadData reads data that we've written to a file.
-//
-// This is useful for development, so that we don't need to read all
-// our data from the network every time we tweak something.
-//
-// This should not be used outside of development, since you'll be
-// working with stale data.
-func ReadData(arvLogger *logger.Logger,
- readCollections *collection.ReadCollections,
- keepServerInfo *keep.ReadServers) error {
- if readDataFrom == "" {
- return fmt.Errorf("ReadData() called with empty filename.")
- }
- summaryFile, err := os.Open(readDataFrom)
- if err != nil {
- return err
- }
- defer summaryFile.Close()
-
- dec := gob.NewDecoder(summaryFile)
- data := serializedData{}
- err = dec.Decode(&data)
- if err != nil {
- return err
- }
-
- // re-summarize data, so that we can update our summarizing
- // functions without needing to do all our network i/o
- data.ReadCollections.Summarize(arvLogger)
- data.KeepServerInfo.Summarize(arvLogger)
-
- *readCollections = data.ReadCollections
- *keepServerInfo = data.KeepServerInfo
- log.Printf("Read summary data from: %s", readDataFrom)
- return nil
-}
+++ /dev/null
-// Code for generating pull lists as described in https://arvados.org/projects/arvados/wiki/Keep_Design_Doc#Pull-List
-
-package summary
-
-import (
- "encoding/json"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
- "git.curoverse.com/arvados.git/sdk/go/logger"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "log"
- "os"
- "strings"
-)
-
-// Locator is a block digest
-type Locator blockdigest.DigestWithSize
-
-// MarshalJSON encoding
-func (l Locator) MarshalJSON() ([]byte, error) {
- return []byte("\"" + blockdigest.DigestWithSize(l).String() + "\""), nil
-}
-
-// PullRequest represents one entry in the Pull List
-type PullRequest struct {
- Locator Locator `json:"locator"`
- Servers []string `json:"servers"`
-}
-
-// PullList for a particular server
-type PullList []PullRequest
-
-// PullListByLocator implements sort.Interface for PullList based on
-// the Digest.
-type PullListByLocator PullList
-
-func (a PullListByLocator) Len() int { return len(a) }
-func (a PullListByLocator) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a PullListByLocator) Less(i, j int) bool {
- di, dj := a[i].Locator.Digest, a[j].Locator.Digest
- if di.H < dj.H {
- return true
- } else if di.H == dj.H {
- if di.L < dj.L {
- return true
- } else if di.L == dj.L {
- return a[i].Locator.Size < a[j].Locator.Size
- }
- }
- return false
-}
-
-// PullServers struct
-// For a given under-replicated block, this structure represents which
-// servers should pull the specified block and which servers they can
-// pull it from.
-type PullServers struct {
- To []string // Servers that should pull the specified block
- From []string // Servers that already contain the specified block
-}
-
-// ComputePullServers creates a map from block locator to PullServers
-// with one entry for each under-replicated block.
-//
-// This method ignores zero-replica blocks since there are no servers
-// to pull them from, so callers should feel free to omit them, but
-// this function will ignore them if they are provided.
-func ComputePullServers(kc *keepclient.KeepClient,
- keepServerInfo *keep.ReadServers,
- blockToDesiredReplication map[blockdigest.DigestWithSize]int,
- underReplicated BlockSet) (m map[Locator]PullServers) {
- m = map[Locator]PullServers{}
- // We use CanonicalString to avoid filling memory with duplicate
- // copies of the same string.
- var cs CanonicalString
-
- // Servers that are writeable
- writableServers := map[string]struct{}{}
- for _, url := range kc.WritableLocalRoots() {
- writableServers[cs.Get(url)] = struct{}{}
- }
-
- for block := range underReplicated {
- serversStoringBlock := keepServerInfo.BlockToServers[block]
- numCopies := len(serversStoringBlock)
- numCopiesMissing := blockToDesiredReplication[block] - numCopies
- if numCopiesMissing > 0 {
- // We expect this to always be true, since the block was listed
- // in underReplicated.
-
- if numCopies > 0 {
- // Not much we can do with blocks with no copies.
-
- // A server's host-port string appears as a key in this map
- // iff it contains the block.
- serverHasBlock := map[string]struct{}{}
- for _, info := range serversStoringBlock {
- sa := keepServerInfo.KeepServerIndexToAddress[info.ServerIndex]
- serverHasBlock[cs.Get(sa.URL())] = struct{}{}
- }
-
- roots := keepclient.NewRootSorter(kc.LocalRoots(),
- block.String()).GetSortedRoots()
-
- l := Locator(block)
- m[l] = CreatePullServers(cs, serverHasBlock, writableServers,
- roots, numCopiesMissing)
- }
- }
- }
- return m
-}
-
-// CreatePullServers creates a pull list in which the To and From
-// fields preserve the ordering of sorted servers and the contents
-// are all canonical strings.
-func CreatePullServers(cs CanonicalString,
- serverHasBlock map[string]struct{},
- writableServers map[string]struct{},
- sortedServers []string,
- maxToFields int) (ps PullServers) {
-
- ps = PullServers{
- To: make([]string, 0, maxToFields),
- From: make([]string, 0, len(serverHasBlock)),
- }
-
- for _, host := range sortedServers {
- // Strip the protocol portion of the url.
- // Use the canonical copy of the string to avoid memory waste.
- server := cs.Get(host)
- _, hasBlock := serverHasBlock[server]
- if hasBlock {
- // The from field should include the protocol.
- ps.From = append(ps.From, cs.Get(host))
- } else if len(ps.To) < maxToFields {
- _, writable := writableServers[host]
- if writable {
- ps.To = append(ps.To, server)
- }
- }
- }
-
- return
-}
-
-// RemoveProtocolPrefix strips the protocol prefix from a url.
-func RemoveProtocolPrefix(url string) string {
- return url[(strings.LastIndex(url, "/") + 1):]
-}
-
-// BuildPullLists produces a PullList for each keep server.
-func BuildPullLists(lps map[Locator]PullServers) (spl map[string]PullList) {
- spl = map[string]PullList{}
- // We don't worry about canonicalizing our strings here, because we
- // assume lps was created by ComputePullServers() which already
- // canonicalized the strings for us.
- for locator, pullServers := range lps {
- for _, destination := range pullServers.To {
- pullList, pullListExists := spl[destination]
- if !pullListExists {
- pullList = PullList{}
- }
- spl[destination] = append(pullList,
- PullRequest{Locator: locator, Servers: pullServers.From})
- }
- }
- return
-}
-
-// WritePullLists writes each pull list to a file.
-// The filename is based on the hostname.
-//
-// This is just a hack for prototyping, it is not expected to be used
-// in production.
-func WritePullLists(arvLogger *logger.Logger,
- pullLists map[string]PullList,
- dryRun bool) error {
- r := strings.NewReplacer(":", ".")
-
- for host, list := range pullLists {
- if arvLogger != nil {
- // We need a local variable because Update doesn't call our mutator func until later,
- // when our list variable might have been reused by the next loop iteration.
- host := host
- listLen := len(list)
- arvLogger.Update(func(p map[string]interface{}, e map[string]interface{}) {
- pullListInfo := logger.GetOrCreateMap(p, "pull_list_len")
- pullListInfo[host] = listLen
- })
- }
-
- if dryRun {
- log.Print("dry run, not sending pull list to service %s with %d blocks", host, len(list))
- continue
- }
-
- filename := fmt.Sprintf("pull_list.%s", r.Replace(RemoveProtocolPrefix(host)))
- pullListFile, err := os.Create(filename)
- if err != nil {
- return err
- }
- defer pullListFile.Close()
-
- enc := json.NewEncoder(pullListFile)
- err = enc.Encode(list)
- if err != nil {
- return err
- }
- log.Printf("Wrote pull list to %s.", filename)
- }
-
- return nil
-}
+++ /dev/null
-package summary
-
-import (
- "encoding/json"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- . "gopkg.in/check.v1"
- "sort"
- "testing"
-)
-
-// Gocheck boilerplate
-func TestPullLists(t *testing.T) {
- TestingT(t)
-}
-
-type PullSuite struct{}
-
-var _ = Suite(&PullSuite{})
-
-// Helper method to declare string sets more succinctly
-// Could be placed somewhere more general.
-func stringSet(slice ...string) (m map[string]struct{}) {
- m = map[string]struct{}{}
- for _, s := range slice {
- m[s] = struct{}{}
- }
- return
-}
-
-func (s *PullSuite) TestPullListPrintsJSONCorrectly(c *C) {
- pl := PullList{PullRequest{
- Locator: Locator(blockdigest.MakeTestDigestSpecifySize(0xBadBeef, 56789)),
- Servers: []string{"keep0.qr1hi.arvadosapi.com:25107",
- "keep1.qr1hi.arvadosapi.com:25108"}}}
-
- b, err := json.Marshal(pl)
- c.Assert(err, IsNil)
- expectedOutput := `[{"locator":"0000000000000000000000000badbeef+56789",` +
- `"servers":["keep0.qr1hi.arvadosapi.com:25107",` +
- `"keep1.qr1hi.arvadosapi.com:25108"]}]`
- c.Check(string(b), Equals, expectedOutput)
-}
-
-func (s *PullSuite) TestCreatePullServers(c *C) {
- var cs CanonicalString
- c.Check(
- CreatePullServers(cs,
- stringSet(),
- stringSet(),
- []string{},
- 5),
- DeepEquals,
- PullServers{To: []string{}, From: []string{}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet(),
- []string{},
- 5),
- DeepEquals,
- PullServers{To: []string{}, From: []string{}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep0:25107"),
- []string{"https://keep0:25107"},
- 5),
- DeepEquals,
- PullServers{To: []string{}, From: []string{"https://keep0:25107"}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"),
- []string{"https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"},
- 5),
- DeepEquals,
- PullServers{To: []string{"https://keep3:25110", "https://keep2:25109"},
- From: []string{"https://keep1:25108", "https://keep0:25107"}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep3:25110", "https://keep1:25108", "https://keep0:25107"),
- []string{"https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"},
- 5),
- DeepEquals,
- PullServers{To: []string{"https://keep3:25110"},
- From: []string{"https://keep1:25108", "https://keep0:25107"}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"),
- []string{"https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"},
- 1),
- DeepEquals,
- PullServers{To: []string{"https://keep3:25110"},
- From: []string{"https://keep1:25108", "https://keep0:25107"}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep3:25110", "https://keep2:25109",
- "https://keep1:25108", "https://keep0:25107"),
- []string{"https://keep3:25110", "https://keep2:25109",
- "https://keep1:25108", "https://keep0:25107"},
- 1),
- DeepEquals,
- PullServers{To: []string{"https://keep3:25110"},
- From: []string{"https://keep1:25108", "https://keep0:25107"}})
-
- c.Check(
- CreatePullServers(cs,
- stringSet("https://keep0:25107", "https://keep1:25108"),
- stringSet("https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"),
- []string{"https://keep3:25110", "https://keep2:25109", "https://keep1:25108", "https://keep0:25107"},
- 0),
- DeepEquals,
- PullServers{To: []string{},
- From: []string{"https://keep1:25108", "https://keep0:25107"}})
-}
-
-// Checks whether two pull list maps are equal. Since pull lists are
-// ordered arbitrarily, we need to sort them by digest before
-// comparing them for deep equality.
-type pullListMapEqualsChecker struct {
- *CheckerInfo
-}
-
-func (c *pullListMapEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
- obtained, ok := params[0].(map[string]PullList)
- if !ok {
- return false, "First parameter is not a PullList map"
- }
- expected, ok := params[1].(map[string]PullList)
- if !ok {
- return false, "Second parameter is not a PullList map"
- }
-
- for _, v := range obtained {
- sort.Sort(PullListByLocator(v))
- }
- for _, v := range expected {
- sort.Sort(PullListByLocator(v))
- }
-
- return DeepEquals.Check(params, names)
-}
-
-var PullListMapEquals Checker = &pullListMapEqualsChecker{&CheckerInfo{
- Name: "PullListMapEquals",
- Params: []string{"obtained", "expected"},
-}}
-
-func (s *PullSuite) TestBuildPullLists(c *C) {
- c.Check(
- BuildPullLists(map[Locator]PullServers{}),
- PullListMapEquals,
- map[string]PullList{})
-
- locator1 := Locator{Digest: blockdigest.MakeTestBlockDigest(0xBadBeef)}
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {To: []string{}, From: []string{}}}),
- PullListMapEquals,
- map[string]PullList{})
-
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {To: []string{}, From: []string{"f1", "f2"}}}),
- PullListMapEquals,
- map[string]PullList{})
-
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {To: []string{"t1"}, From: []string{"f1", "f2"}}}),
- PullListMapEquals,
- map[string]PullList{
- "t1": {PullRequest{locator1, []string{"f1", "f2"}}}})
-
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {To: []string{"t1"}, From: []string{}}}),
- PullListMapEquals,
- map[string]PullList{"t1": {
- PullRequest{locator1, []string{}}}})
-
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {
- To: []string{"t1", "t2"},
- From: []string{"f1", "f2"},
- }}),
- PullListMapEquals,
- map[string]PullList{
- "t1": {PullRequest{locator1, []string{"f1", "f2"}}},
- "t2": {PullRequest{locator1, []string{"f1", "f2"}}},
- })
-
- locator2 := Locator{Digest: blockdigest.MakeTestBlockDigest(0xCabbed)}
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {To: []string{"t1"}, From: []string{"f1", "f2"}},
- locator2: {To: []string{"t2"}, From: []string{"f3", "f4"}}}),
- PullListMapEquals,
- map[string]PullList{
- "t1": {PullRequest{locator1, []string{"f1", "f2"}}},
- "t2": {PullRequest{locator2, []string{"f3", "f4"}}},
- })
-
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {
- To: []string{"t1"},
- From: []string{"f1", "f2"}},
- locator2: {
- To: []string{"t2", "t1"},
- From: []string{"f3", "f4"}},
- }),
- PullListMapEquals,
- map[string]PullList{
- "t1": {
- PullRequest{locator1, []string{"f1", "f2"}},
- PullRequest{locator2, []string{"f3", "f4"}},
- },
- "t2": {
- PullRequest{locator2, []string{"f3", "f4"}},
- },
- })
-
- locator3 := Locator{Digest: blockdigest.MakeTestBlockDigest(0xDeadBeef)}
- locator4 := Locator{Digest: blockdigest.MakeTestBlockDigest(0xFedBeef)}
- c.Check(
- BuildPullLists(map[Locator]PullServers{
- locator1: {
- To: []string{"t1"},
- From: []string{"f1", "f2"}},
- locator2: {
- To: []string{"t2", "t1"},
- From: []string{"f3", "f4"}},
- locator3: {
- To: []string{"t3", "t2", "t1"},
- From: []string{"f4", "f5"}},
- locator4: {
- To: []string{"t4", "t3", "t2", "t1"},
- From: []string{"f1", "f5"}},
- }),
- PullListMapEquals,
- map[string]PullList{
- "t1": {
- PullRequest{locator1, []string{"f1", "f2"}},
- PullRequest{locator2, []string{"f3", "f4"}},
- PullRequest{locator3, []string{"f4", "f5"}},
- PullRequest{locator4, []string{"f1", "f5"}},
- },
- "t2": {
- PullRequest{locator2, []string{"f3", "f4"}},
- PullRequest{locator3, []string{"f4", "f5"}},
- PullRequest{locator4, []string{"f1", "f5"}},
- },
- "t3": {
- PullRequest{locator3, []string{"f4", "f5"}},
- PullRequest{locator4, []string{"f1", "f5"}},
- },
- "t4": {
- PullRequest{locator4, []string{"f1", "f5"}},
- },
- })
-}
+++ /dev/null
-// Summarizes Collection Data and Keep Server Contents.
-
-package summary
-
-// TODO(misha): Check size of blocks as well as their digest.
-
-import (
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/services/datamanager/collection"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "sort"
-)
-
-// BlockSet is a map of blocks
-type BlockSet map[blockdigest.DigestWithSize]struct{}
-
-// Insert adds a single block to the set.
-func (bs BlockSet) Insert(digest blockdigest.DigestWithSize) {
- bs[digest] = struct{}{}
-}
-
-// Union adds a set of blocks to the set.
-func (bs BlockSet) Union(obs BlockSet) {
- for k, v := range obs {
- bs[k] = v
- }
-}
-
-// CollectionIndexSet is used to save space. To convert to and from
-// the uuid, use collection.ReadCollections' fields
-// CollectionIndexToUUID and CollectionUUIDToIndex.
-type CollectionIndexSet map[int]struct{}
-
-// Insert adds a single collection to the set. The collection is specified by
-// its index.
-func (cis CollectionIndexSet) Insert(collectionIndex int) {
- cis[collectionIndex] = struct{}{}
-}
-
-// ToCollectionIndexSet gets block to collection indices
-func (bs BlockSet) ToCollectionIndexSet(
- readCollections collection.ReadCollections,
- collectionIndexSet *CollectionIndexSet) {
- for block := range bs {
- for _, collectionIndex := range readCollections.BlockToCollectionIndices[block] {
- collectionIndexSet.Insert(collectionIndex)
- }
- }
-}
-
-// ReplicationLevels struct
-// Keeps track of the requested and actual replication levels.
-// Currently this is only used for blocks but could easily be used for
-// collections as well.
-type ReplicationLevels struct {
- // The requested replication level.
- // For Blocks this is the maximum replication level among all the
- // collections this block belongs to.
- Requested int
-
- // The actual number of keep servers this is on.
- Actual int
-}
-
-// ReplicationLevelBlockSetMap maps from replication levels to their blocks.
-type ReplicationLevelBlockSetMap map[ReplicationLevels]BlockSet
-
-// ReplicationLevelBlockCount is an individual entry from ReplicationLevelBlockSetMap
-// which only reports the number of blocks, not which blocks.
-type ReplicationLevelBlockCount struct {
- Levels ReplicationLevels
- Count int
-}
-
-// ReplicationLevelBlockSetSlice is an ordered list of ReplicationLevelBlockCount useful for reporting.
-type ReplicationLevelBlockSetSlice []ReplicationLevelBlockCount
-
-// ReplicationSummary sturct
-type ReplicationSummary struct {
- CollectionBlocksNotInKeep BlockSet
- UnderReplicatedBlocks BlockSet
- OverReplicatedBlocks BlockSet
- CorrectlyReplicatedBlocks BlockSet
- KeepBlocksNotInCollections BlockSet
-
- CollectionsNotFullyInKeep CollectionIndexSet
- UnderReplicatedCollections CollectionIndexSet
- OverReplicatedCollections CollectionIndexSet
- CorrectlyReplicatedCollections CollectionIndexSet
-}
-
-// ReplicationSummaryCounts struct counts the elements in each set in ReplicationSummary.
-type ReplicationSummaryCounts struct {
- CollectionBlocksNotInKeep int
- UnderReplicatedBlocks int
- OverReplicatedBlocks int
- CorrectlyReplicatedBlocks int
- KeepBlocksNotInCollections int
- CollectionsNotFullyInKeep int
- UnderReplicatedCollections int
- OverReplicatedCollections int
- CorrectlyReplicatedCollections int
-}
-
-// GetOrCreate gets the BlockSet for a given set of ReplicationLevels,
-// creating it if it doesn't already exist.
-func (rlbs ReplicationLevelBlockSetMap) GetOrCreate(
- repLevels ReplicationLevels) (bs BlockSet) {
- bs, exists := rlbs[repLevels]
- if !exists {
- bs = make(BlockSet)
- rlbs[repLevels] = bs
- }
- return
-}
-
-// Insert adds a block to the set for a given replication level.
-func (rlbs ReplicationLevelBlockSetMap) Insert(
- repLevels ReplicationLevels,
- block blockdigest.DigestWithSize) {
- rlbs.GetOrCreate(repLevels).Insert(block)
-}
-
-// Union adds a set of blocks to the set for a given replication level.
-func (rlbs ReplicationLevelBlockSetMap) Union(
- repLevels ReplicationLevels,
- bs BlockSet) {
- rlbs.GetOrCreate(repLevels).Union(bs)
-}
-
-// Counts outputs a sorted list of ReplicationLevelBlockCounts.
-func (rlbs ReplicationLevelBlockSetMap) Counts() (
- sorted ReplicationLevelBlockSetSlice) {
- sorted = make(ReplicationLevelBlockSetSlice, len(rlbs))
- i := 0
- for levels, set := range rlbs {
- sorted[i] = ReplicationLevelBlockCount{Levels: levels, Count: len(set)}
- i++
- }
- sort.Sort(sorted)
- return
-}
-
-// Implemented to meet sort.Interface
-func (rlbss ReplicationLevelBlockSetSlice) Len() int {
- return len(rlbss)
-}
-
-// Implemented to meet sort.Interface
-func (rlbss ReplicationLevelBlockSetSlice) Less(i, j int) bool {
- return rlbss[i].Levels.Requested < rlbss[j].Levels.Requested ||
- (rlbss[i].Levels.Requested == rlbss[j].Levels.Requested &&
- rlbss[i].Levels.Actual < rlbss[j].Levels.Actual)
-}
-
-// Implemented to meet sort.Interface
-func (rlbss ReplicationLevelBlockSetSlice) Swap(i, j int) {
- rlbss[i], rlbss[j] = rlbss[j], rlbss[i]
-}
-
-// ComputeCounts returns ReplicationSummaryCounts
-func (rs ReplicationSummary) ComputeCounts() (rsc ReplicationSummaryCounts) {
- // TODO(misha): Consider rewriting this method to iterate through
- // the fields using reflection, instead of explictily listing the
- // fields as we do now.
- rsc.CollectionBlocksNotInKeep = len(rs.CollectionBlocksNotInKeep)
- rsc.UnderReplicatedBlocks = len(rs.UnderReplicatedBlocks)
- rsc.OverReplicatedBlocks = len(rs.OverReplicatedBlocks)
- rsc.CorrectlyReplicatedBlocks = len(rs.CorrectlyReplicatedBlocks)
- rsc.KeepBlocksNotInCollections = len(rs.KeepBlocksNotInCollections)
- rsc.CollectionsNotFullyInKeep = len(rs.CollectionsNotFullyInKeep)
- rsc.UnderReplicatedCollections = len(rs.UnderReplicatedCollections)
- rsc.OverReplicatedCollections = len(rs.OverReplicatedCollections)
- rsc.CorrectlyReplicatedCollections = len(rs.CorrectlyReplicatedCollections)
- return rsc
-}
-
-// PrettyPrint ReplicationSummaryCounts
-func (rsc ReplicationSummaryCounts) PrettyPrint() string {
- return fmt.Sprintf("Replication Block Counts:"+
- "\n Missing From Keep: %d, "+
- "\n Under Replicated: %d, "+
- "\n Over Replicated: %d, "+
- "\n Replicated Just Right: %d, "+
- "\n Not In Any Collection: %d. "+
- "\nReplication Collection Counts:"+
- "\n Missing From Keep: %d, "+
- "\n Under Replicated: %d, "+
- "\n Over Replicated: %d, "+
- "\n Replicated Just Right: %d.",
- rsc.CollectionBlocksNotInKeep,
- rsc.UnderReplicatedBlocks,
- rsc.OverReplicatedBlocks,
- rsc.CorrectlyReplicatedBlocks,
- rsc.KeepBlocksNotInCollections,
- rsc.CollectionsNotFullyInKeep,
- rsc.UnderReplicatedCollections,
- rsc.OverReplicatedCollections,
- rsc.CorrectlyReplicatedCollections)
-}
-
-// BucketReplication returns ReplicationLevelBlockSetMap
-func BucketReplication(readCollections collection.ReadCollections,
- keepServerInfo keep.ReadServers) (rlbs ReplicationLevelBlockSetMap) {
- rlbs = make(ReplicationLevelBlockSetMap)
-
- for block, requestedReplication := range readCollections.BlockToDesiredReplication {
- rlbs.Insert(
- ReplicationLevels{
- Requested: requestedReplication,
- Actual: len(keepServerInfo.BlockToServers[block])},
- block)
- }
-
- for block, servers := range keepServerInfo.BlockToServers {
- if 0 == readCollections.BlockToDesiredReplication[block] {
- rlbs.Insert(
- ReplicationLevels{Requested: 0, Actual: len(servers)},
- block)
- }
- }
- return
-}
-
-// SummarizeBuckets reads collections and summarizes
-func (rlbs ReplicationLevelBlockSetMap) SummarizeBuckets(
- readCollections collection.ReadCollections) (
- rs ReplicationSummary) {
- rs.CollectionBlocksNotInKeep = make(BlockSet)
- rs.UnderReplicatedBlocks = make(BlockSet)
- rs.OverReplicatedBlocks = make(BlockSet)
- rs.CorrectlyReplicatedBlocks = make(BlockSet)
- rs.KeepBlocksNotInCollections = make(BlockSet)
-
- rs.CollectionsNotFullyInKeep = make(CollectionIndexSet)
- rs.UnderReplicatedCollections = make(CollectionIndexSet)
- rs.OverReplicatedCollections = make(CollectionIndexSet)
- rs.CorrectlyReplicatedCollections = make(CollectionIndexSet)
-
- for levels, bs := range rlbs {
- if levels.Actual == 0 {
- rs.CollectionBlocksNotInKeep.Union(bs)
- } else if levels.Requested == 0 {
- rs.KeepBlocksNotInCollections.Union(bs)
- } else if levels.Actual < levels.Requested {
- rs.UnderReplicatedBlocks.Union(bs)
- } else if levels.Actual > levels.Requested {
- rs.OverReplicatedBlocks.Union(bs)
- } else {
- rs.CorrectlyReplicatedBlocks.Union(bs)
- }
- }
-
- rs.CollectionBlocksNotInKeep.ToCollectionIndexSet(readCollections,
- &rs.CollectionsNotFullyInKeep)
- // Since different collections can specify different replication
- // levels, the fact that a block is under-replicated does not imply
- // that all collections that it belongs to are under-replicated, but
- // we'll ignore that for now.
- // TODO(misha): Fix this and report the correct set of collections.
- rs.UnderReplicatedBlocks.ToCollectionIndexSet(readCollections,
- &rs.UnderReplicatedCollections)
- rs.OverReplicatedBlocks.ToCollectionIndexSet(readCollections,
- &rs.OverReplicatedCollections)
-
- for i := range readCollections.CollectionIndexToUUID {
- if _, notInKeep := rs.CollectionsNotFullyInKeep[i]; notInKeep {
- } else if _, underReplicated := rs.UnderReplicatedCollections[i]; underReplicated {
- } else if _, overReplicated := rs.OverReplicatedCollections[i]; overReplicated {
- } else {
- rs.CorrectlyReplicatedCollections.Insert(i)
- }
- }
-
- return
-}
+++ /dev/null
-package summary
-
-import (
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/services/datamanager/collection"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "reflect"
- "sort"
- "testing"
-)
-
-func BlockSetFromSlice(digests []int) (bs BlockSet) {
- bs = make(BlockSet)
- for _, digest := range digests {
- bs.Insert(blockdigest.MakeTestDigestWithSize(digest))
- }
- return
-}
-
-func CollectionIndexSetFromSlice(indices []int) (cis CollectionIndexSet) {
- cis = make(CollectionIndexSet)
- for _, index := range indices {
- cis.Insert(index)
- }
- return
-}
-
-func (cis CollectionIndexSet) ToSlice() (ints []int) {
- ints = make([]int, len(cis))
- i := 0
- for collectionIndex := range cis {
- ints[i] = collectionIndex
- i++
- }
- sort.Ints(ints)
- return
-}
-
-// Helper method to meet interface expected by older tests.
-func SummarizeReplication(readCollections collection.ReadCollections,
- keepServerInfo keep.ReadServers) (rs ReplicationSummary) {
- return BucketReplication(readCollections, keepServerInfo).
- SummarizeBuckets(readCollections)
-}
-
-// Takes a map from block digest to replication level and represents
-// it in a keep.ReadServers structure.
-func SpecifyReplication(digestToReplication map[int]int) (rs keep.ReadServers) {
- rs.BlockToServers = make(map[blockdigest.DigestWithSize][]keep.BlockServerInfo)
- for digest, replication := range digestToReplication {
- rs.BlockToServers[blockdigest.MakeTestDigestWithSize(digest)] =
- make([]keep.BlockServerInfo, replication)
- }
- return
-}
-
-// Verifies that
-// blocks.ToCollectionIndexSet(rc.BlockToCollectionIndices) returns
-// expectedCollections.
-func VerifyToCollectionIndexSet(
- t *testing.T,
- blocks []int,
- blockToCollectionIndices map[int][]int,
- expectedCollections []int) {
-
- expected := CollectionIndexSetFromSlice(expectedCollections)
-
- rc := collection.ReadCollections{
- BlockToCollectionIndices: map[blockdigest.DigestWithSize][]int{},
- }
- for digest, indices := range blockToCollectionIndices {
- rc.BlockToCollectionIndices[blockdigest.MakeTestDigestWithSize(digest)] = indices
- }
-
- returned := make(CollectionIndexSet)
- BlockSetFromSlice(blocks).ToCollectionIndexSet(rc, &returned)
-
- if !reflect.DeepEqual(returned, expected) {
- t.Errorf("Expected %v.ToCollectionIndexSet(%v) to return \n %v \n but instead received \n %v",
- blocks,
- blockToCollectionIndices,
- expectedCollections,
- returned.ToSlice())
- }
-}
-
-func TestToCollectionIndexSet(t *testing.T) {
- VerifyToCollectionIndexSet(t, []int{6}, map[int][]int{6: {0}}, []int{0})
- VerifyToCollectionIndexSet(t, []int{4}, map[int][]int{4: {1}}, []int{1})
- VerifyToCollectionIndexSet(t, []int{4}, map[int][]int{4: {1, 9}}, []int{1, 9})
- VerifyToCollectionIndexSet(t, []int{5, 6},
- map[int][]int{5: {2, 3}, 6: {3, 4}},
- []int{2, 3, 4})
- VerifyToCollectionIndexSet(t, []int{5, 6},
- map[int][]int{5: {8}, 6: {4}},
- []int{4, 8})
- VerifyToCollectionIndexSet(t, []int{6}, map[int][]int{5: {0}}, []int{})
-}
-
-func TestSimpleSummary(t *testing.T) {
- rc := collection.MakeTestReadCollections([]collection.TestCollectionSpec{
- {ReplicationLevel: 1, Blocks: []int{1, 2}},
- })
- rc.Summarize(nil)
- cIndex := rc.CollectionIndicesForTesting()
-
- keepInfo := SpecifyReplication(map[int]int{1: 1, 2: 1})
-
- expectedSummary := ReplicationSummary{
- CollectionBlocksNotInKeep: BlockSet{},
- UnderReplicatedBlocks: BlockSet{},
- OverReplicatedBlocks: BlockSet{},
- CorrectlyReplicatedBlocks: BlockSetFromSlice([]int{1, 2}),
- KeepBlocksNotInCollections: BlockSet{},
-
- CollectionsNotFullyInKeep: CollectionIndexSet{},
- UnderReplicatedCollections: CollectionIndexSet{},
- OverReplicatedCollections: CollectionIndexSet{},
- CorrectlyReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[0]}),
- }
-
- returnedSummary := SummarizeReplication(rc, keepInfo)
-
- if !reflect.DeepEqual(returnedSummary, expectedSummary) {
- t.Fatalf("Expected returnedSummary to look like %+v but instead it is %+v", expectedSummary, returnedSummary)
- }
-}
-
-func TestMissingBlock(t *testing.T) {
- rc := collection.MakeTestReadCollections([]collection.TestCollectionSpec{
- {ReplicationLevel: 1, Blocks: []int{1, 2}},
- })
- rc.Summarize(nil)
- cIndex := rc.CollectionIndicesForTesting()
-
- keepInfo := SpecifyReplication(map[int]int{1: 1})
-
- expectedSummary := ReplicationSummary{
- CollectionBlocksNotInKeep: BlockSetFromSlice([]int{2}),
- UnderReplicatedBlocks: BlockSet{},
- OverReplicatedBlocks: BlockSet{},
- CorrectlyReplicatedBlocks: BlockSetFromSlice([]int{1}),
- KeepBlocksNotInCollections: BlockSet{},
-
- CollectionsNotFullyInKeep: CollectionIndexSetFromSlice([]int{cIndex[0]}),
- UnderReplicatedCollections: CollectionIndexSet{},
- OverReplicatedCollections: CollectionIndexSet{},
- CorrectlyReplicatedCollections: CollectionIndexSet{},
- }
-
- returnedSummary := SummarizeReplication(rc, keepInfo)
-
- if !reflect.DeepEqual(returnedSummary, expectedSummary) {
- t.Fatalf("Expected returnedSummary to look like %+v but instead it is %+v",
- expectedSummary,
- returnedSummary)
- }
-}
-
-func TestUnderAndOverReplicatedBlocks(t *testing.T) {
- rc := collection.MakeTestReadCollections([]collection.TestCollectionSpec{
- {ReplicationLevel: 2, Blocks: []int{1, 2}},
- })
- rc.Summarize(nil)
- cIndex := rc.CollectionIndicesForTesting()
-
- keepInfo := SpecifyReplication(map[int]int{1: 1, 2: 3})
-
- expectedSummary := ReplicationSummary{
- CollectionBlocksNotInKeep: BlockSet{},
- UnderReplicatedBlocks: BlockSetFromSlice([]int{1}),
- OverReplicatedBlocks: BlockSetFromSlice([]int{2}),
- CorrectlyReplicatedBlocks: BlockSet{},
- KeepBlocksNotInCollections: BlockSet{},
-
- CollectionsNotFullyInKeep: CollectionIndexSet{},
- UnderReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[0]}),
- OverReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[0]}),
- CorrectlyReplicatedCollections: CollectionIndexSet{},
- }
-
- returnedSummary := SummarizeReplication(rc, keepInfo)
-
- if !reflect.DeepEqual(returnedSummary, expectedSummary) {
- t.Fatalf("Expected returnedSummary to look like %+v but instead it is %+v",
- expectedSummary,
- returnedSummary)
- }
-}
-
-func TestMixedReplication(t *testing.T) {
- rc := collection.MakeTestReadCollections([]collection.TestCollectionSpec{
- {ReplicationLevel: 1, Blocks: []int{1, 2}},
- {ReplicationLevel: 1, Blocks: []int{3, 4}},
- {ReplicationLevel: 2, Blocks: []int{5, 6}},
- })
- rc.Summarize(nil)
- cIndex := rc.CollectionIndicesForTesting()
-
- keepInfo := SpecifyReplication(map[int]int{1: 1, 2: 1, 3: 1, 5: 1, 6: 3, 7: 2})
-
- expectedSummary := ReplicationSummary{
- CollectionBlocksNotInKeep: BlockSetFromSlice([]int{4}),
- UnderReplicatedBlocks: BlockSetFromSlice([]int{5}),
- OverReplicatedBlocks: BlockSetFromSlice([]int{6}),
- CorrectlyReplicatedBlocks: BlockSetFromSlice([]int{1, 2, 3}),
- KeepBlocksNotInCollections: BlockSetFromSlice([]int{7}),
-
- CollectionsNotFullyInKeep: CollectionIndexSetFromSlice([]int{cIndex[1]}),
- UnderReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[2]}),
- OverReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[2]}),
- CorrectlyReplicatedCollections: CollectionIndexSetFromSlice([]int{cIndex[0]}),
- }
-
- returnedSummary := SummarizeReplication(rc, keepInfo)
-
- if !reflect.DeepEqual(returnedSummary, expectedSummary) {
- t.Fatalf("Expected returnedSummary to look like: \n%+v but instead it is: \n%+v. Index to UUID is %v. BlockToCollectionIndices is %v.", expectedSummary, returnedSummary, rc.CollectionIndexToUUID, rc.BlockToCollectionIndices)
- }
-}
+++ /dev/null
-// Code for generating trash lists
-
-package summary
-
-import (
- "errors"
- "fmt"
- "git.curoverse.com/arvados.git/sdk/go/keepclient"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- "time"
-)
-
-// BuildTrashLists builds list of blocks to be sent to trash queue
-func BuildTrashLists(kc *keepclient.KeepClient,
- keepServerInfo *keep.ReadServers,
- keepBlocksNotInCollections BlockSet) (m map[string]keep.TrashList, err error) {
-
- // Servers that are writeable
- writableServers := map[string]struct{}{}
- for _, url := range kc.WritableLocalRoots() {
- writableServers[url] = struct{}{}
- }
-
- _ttl, err := kc.Arvados.Discovery("blobSignatureTtl")
- if err != nil {
- return nil, errors.New(fmt.Sprintf("Failed to get blobSignatureTtl, can't build trash lists: %v", err))
- }
-
- ttl := int64(_ttl.(float64))
-
- // expire unreferenced blocks more than "ttl" seconds old.
- expiry := time.Now().UTC().UnixNano() - ttl*1e9
-
- return buildTrashListsInternal(writableServers, keepServerInfo, expiry, keepBlocksNotInCollections), nil
-}
-
-func buildTrashListsInternal(writableServers map[string]struct{},
- keepServerInfo *keep.ReadServers,
- expiry int64,
- keepBlocksNotInCollections BlockSet) (m map[string]keep.TrashList) {
-
- m = make(map[string]keep.TrashList)
-
- for block := range keepBlocksNotInCollections {
- for _, blockOnServer := range keepServerInfo.BlockToServers[block] {
- if blockOnServer.Mtime >= expiry {
- continue
- }
-
- // block is older than expire cutoff
- srv := keepServerInfo.KeepServerIndexToAddress[blockOnServer.ServerIndex].String()
-
- if _, writable := writableServers[srv]; !writable {
- continue
- }
-
- m[srv] = append(m[srv], keep.TrashRequest{Locator: block.Digest.String(), BlockMtime: blockOnServer.Mtime})
- }
- }
- return
-
-}
+++ /dev/null
-package summary
-
-import (
- "git.curoverse.com/arvados.git/sdk/go/blockdigest"
- "git.curoverse.com/arvados.git/services/datamanager/keep"
- . "gopkg.in/check.v1"
- "testing"
-)
-
-// Gocheck boilerplate
-func TestTrash(t *testing.T) {
- TestingT(t)
-}
-
-type TrashSuite struct{}
-
-var _ = Suite(&TrashSuite{})
-
-func (s *TrashSuite) TestBuildTrashLists(c *C) {
- var sv0 = keep.ServerAddress{Host: "keep0.example.com", Port: 80}
- var sv1 = keep.ServerAddress{Host: "keep1.example.com", Port: 80}
-
- var block0 = blockdigest.MakeTestDigestWithSize(0xdeadbeef)
- var block1 = blockdigest.MakeTestDigestWithSize(0xfedbeef)
-
- var keepServerInfo = keep.ReadServers{
- KeepServerIndexToAddress: []keep.ServerAddress{sv0, sv1},
- BlockToServers: map[blockdigest.DigestWithSize][]keep.BlockServerInfo{
- block0: {
- {0, 99},
- {1, 101}},
- block1: {
- {0, 99},
- {1, 101}}}}
-
- // only block0 is in delete set
- var bs = make(BlockSet)
- bs[block0] = struct{}{}
-
- // Test trash list where only sv0 is on writable list.
- c.Check(buildTrashListsInternal(
- map[string]struct{}{
- sv0.URL(): {}},
- &keepServerInfo,
- 110,
- bs),
- DeepEquals,
- map[string]keep.TrashList{
- "http://keep0.example.com:80": {keep.TrashRequest{"000000000000000000000000deadbeef", 99}}})
-
- // Test trash list where both sv0 and sv1 are on writable list.
- c.Check(buildTrashListsInternal(
- map[string]struct{}{
- sv0.URL(): {},
- sv1.URL(): {}},
- &keepServerInfo,
- 110,
- bs),
- DeepEquals,
- map[string]keep.TrashList{
- "http://keep0.example.com:80": {keep.TrashRequest{"000000000000000000000000deadbeef", 99}},
- "http://keep1.example.com:80": {keep.TrashRequest{"000000000000000000000000deadbeef", 101}}})
-
- // Test trash list where only block on sv0 is expired
- c.Check(buildTrashListsInternal(
- map[string]struct{}{
- sv0.URL(): {},
- sv1.URL(): {}},
- &keepServerInfo,
- 100,
- bs),
- DeepEquals,
- map[string]keep.TrashList{
- "http://keep0.example.com:80": {keep.TrashRequest{"000000000000000000000000deadbeef", 99}}})
-
-}
# unlimited to avoid deadlocks, see https://arvados.org/issues/3198#note-43 for
# details.
-llfuse.capi._notify_queue = Queue.Queue()
+if hasattr(llfuse, 'capi'):
+ # llfuse < 0.42
+ llfuse.capi._notify_queue = Queue.Queue()
+else:
+ # llfuse >= 0.42
+ llfuse._notify_queue = Queue.Queue()
from fusedir import sanitize_filename, Directory, CollectionDirectory, TmpCollectionDirectory, MagicDirectory, TagsDirectory, ProjectDirectory, SharedDirectory, CollectionDirectoryBase
from fusefile import StringFile, FuseArvadosFile
@catch_exceptions
def destroy(self):
- with llfuse.lock:
- self._shutdown_started.set()
- if self.events:
- self.events.close()
- self.events = None
+ self._shutdown_started.set()
+ if self.events:
+ self.events.close()
+ self.events = None
+ if llfuse.lock.acquire():
+ # llfuse < 0.42
+ self.inodes.clear()
+ llfuse.lock.release()
+ else:
+ # llfuse >= 0.42
self.inodes.clear()
def access(self, inode, mode, ctx):
if 'event_type' not in ev:
return
with llfuse.lock:
+ new_attrs = (ev.get("properties") or {}).get("new_attributes") or {}
+ pdh = new_attrs.get("portable_data_hash")
+ # new_attributes.modified_at currently lacks
+ # subsecond precision (see #6347) so use event_at
+ # which should always be the same.
+ stamp = ev.get("event_at")
+
for item in self.inodes.inode_cache.find_by_uuid(ev["object_uuid"]):
item.invalidate()
- if ev["object_kind"] == "arvados#collection":
- new_attr = (ev.get("properties") and
- ev["properties"].get("new_attributes") and
- ev["properties"]["new_attributes"])
-
- # new_attributes.modified_at currently lacks
- # subsecond precision (see #6347) so use event_at
- # which should always be the same.
- record_version = (
- (ev["event_at"], new_attr["portable_data_hash"])
- if new_attr else None)
-
- item.update(to_record_version=record_version)
+ if stamp and pdh and ev.get("object_kind") == "arvados#collection":
+ item.update(to_record_version=(stamp, pdh))
else:
item.update()
- oldowner = (
- ev.get("properties") and
- ev["properties"].get("old_attributes") and
- ev["properties"]["old_attributes"].get("owner_uuid"))
- newowner = ev["object_owner_uuid"]
+ oldowner = ((ev.get("properties") or {}).get("old_attributes") or {}).get("owner_uuid")
+ newowner = ev.get("object_owner_uuid")
for parent in (
self.inodes.inode_cache.find_by_uuid(oldowner) +
self.inodes.inode_cache.find_by_uuid(newowner)):
parent.invalidate()
parent.update()
-
@catch_exceptions
- def getattr(self, inode):
+ def getattr(self, inode, ctx=None):
if inode not in self.inodes:
raise llfuse.FUSEError(errno.ENOENT)
entry.st_blksize = 512
entry.st_blocks = (entry.st_size/512)+1
- entry.st_atime = int(e.atime())
- entry.st_mtime = int(e.mtime())
- entry.st_ctime = int(e.mtime())
+ if hasattr(entry, 'st_atime_ns'):
+ # llfuse >= 0.42
+ entry.st_atime_ns = int(e.atime() * 1000000000)
+ entry.st_mtime_ns = int(e.mtime() * 1000000000)
+ entry.st_ctime_ns = int(e.mtime() * 1000000000)
+ else:
+ # llfuse < 0.42
+ entry.st_atime = int(e.atime)
+ entry.st_mtime = int(e.mtime)
+ entry.st_ctime = int(e.mtime)
return entry
@catch_exceptions
- def setattr(self, inode, attr):
+ def setattr(self, inode, attr, fields=None, fh=None, ctx=None):
entry = self.getattr(inode)
- e = self.inodes[inode]
+ if fh is not None and fh in self._filehandles:
+ handle = self._filehandles[fh]
+ e = handle.obj
+ else:
+ e = self.inodes[inode]
- if attr.st_size is not None and isinstance(e, FuseArvadosFile):
+ if fields is None:
+ # llfuse < 0.42
+ update_size = attr.st_size is not None
+ else:
+ # llfuse >= 0.42
+ update_size = fields.update_size
+ if update_size and isinstance(e, FuseArvadosFile):
with llfuse.lock_released:
e.arvfile.truncate(attr.st_size)
entry.st_size = e.arvfile.size()
return entry
@catch_exceptions
- def lookup(self, parent_inode, name):
+ def lookup(self, parent_inode, name, ctx=None):
name = unicode(name, self.inodes.encoding)
inode = None
self.inodes.del_entry(ent)
@catch_exceptions
- def open(self, inode, flags):
+ def open(self, inode, flags, ctx=None):
if inode in self.inodes:
p = self.inodes[inode]
else:
self.release(fh)
@catch_exceptions
- def opendir(self, inode):
+ def opendir(self, inode, ctx=None):
_logger.debug("arv-mount opendir: inode %i", inode)
if inode in self.inodes:
e += 1
@catch_exceptions
- def statfs(self):
+ def statfs(self, ctx=None):
st = llfuse.StatvfsData()
st.f_bsize = 128 * 1024
st.f_blocks = 0
return p
@catch_exceptions
- def create(self, inode_parent, name, mode, flags, ctx):
+ def create(self, inode_parent, name, mode, flags, ctx=None):
_logger.debug("arv-mount create: parent_inode %i '%s' %o", inode_parent, name, mode)
p = self._check_writable(inode_parent)
return (fh, self.getattr(f.inode))
@catch_exceptions
- def mkdir(self, inode_parent, name, mode, ctx):
+ def mkdir(self, inode_parent, name, mode, ctx=None):
_logger.debug("arv-mount mkdir: parent_inode %i '%s' %o", inode_parent, name, mode)
p = self._check_writable(inode_parent)
return self.getattr(d.inode)
@catch_exceptions
- def unlink(self, inode_parent, name):
+ def unlink(self, inode_parent, name, ctx=None):
_logger.debug("arv-mount unlink: parent_inode %i '%s'", inode_parent, name)
p = self._check_writable(inode_parent)
p.unlink(name)
@catch_exceptions
- def rmdir(self, inode_parent, name):
+ def rmdir(self, inode_parent, name, ctx=None):
_logger.debug("arv-mount rmdir: parent_inode %i '%s'", inode_parent, name)
p = self._check_writable(inode_parent)
p.rmdir(name)
@catch_exceptions
- def rename(self, inode_parent_old, name_old, inode_parent_new, name_new):
+ def rename(self, inode_parent_old, name_old, inode_parent_new, name_new, ctx=None):
_logger.debug("arv-mount rename: old_parent_inode %i '%s' new_parent_inode %i '%s'", inode_parent_old, name_old, inode_parent_new, name_new)
src = self._check_writable(inode_parent_old)
dest = self._check_writable(inode_parent_new)
--- /dev/null
+import pkg_resources
+
+__version__ = pkg_resources.require('arvados_fuse')[0].version
import arvados.commands._util as arv_cmd
from arvados_fuse import crunchstat
from arvados_fuse import *
+from arvados_fuse._version import __version__
class ArgumentParser(argparse.ArgumentParser):
def __init__(self):
mountpoint before --exec, or mark the end of your --exec arguments
with "--".
""")
+ self.add_argument('--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
self.add_argument('mountpoint', type=str, help="""Mount point.""")
self.add_argument('--allow-other', action='store_true',
help="""Let other users read the mount""")
return self
def __exit__(self, exc_type, exc_value, traceback):
+ if self.operations.events:
+ self.operations.events.close(timeout=self.args.unmount_timeout)
subprocess.call(["fusermount", "-u", "-z", self.args.mountpoint])
self.llfuse_thread.join(timeout=self.args.unmount_timeout)
if self.llfuse_thread.is_alive():
'arvados-python-client >= 0.1.20151118035730',
'llfuse==0.41.1',
'python-daemon',
- 'ciso8601'
+ 'ciso8601',
+ 'setuptools'
],
test_suite='tests',
tests_require=['pbr<1.7.0', 'mock>=1.0', 'PyYAML'],
def tearDown(self):
if self.llfuse_thread:
+ if self.operations.events:
+ self.operations.events.close(timeout=10)
subprocess.call(["fusermount", "-u", "-z", self.mounttmp])
t0 = time.time()
self.llfuse_thread.join(timeout=10)
import arvados_fuse.command
import contextlib
import functools
+import io
import json
import llfuse
import logging
ent = ent[p]
return ent
+ @contextlib.contextmanager
+ def stderrMatches(self, stderr):
+ orig, sys.stderr = sys.stderr, stderr
+ try:
+ yield
+ finally:
+ sys.stderr = orig
+
def check_ent_type(self, cls, *path):
ent = self.lookup(self.mnt, *path)
self.assertEqual(ent.__class__, cls)
run_test_server.fixture('users')['active']['uuid'])
self.assertEqual(True, self.mnt.listen_for_events)
+ def test_version_argument(self):
+ orig, sys.stderr = sys.stderr, io.BytesIO()
+ with self.assertRaises(SystemExit):
+ args = arvados_fuse.command.ArgumentParser().parse_args(['--version'])
+ self.assertRegexpMatches(sys.stderr.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
+ sys.stderr = orig
+
@noexit
@mock.patch('arvados.events.subscribe')
def test_disable_event_listening(self, mock_subscribe):
# check mtime on template
st = os.stat(pipeline_template_path)
- self.assertEqual(st.st_mtime, 1397493304)
+ try:
+ mtime = st.st_mtime_ns / 1000000000
+ except AttributeError:
+ mtime = st.st_mtime
+ self.assertEqual(mtime, 1397493304)
# check mtime on collection
st = os.stat(os.path.join(
self.mounttmp,
'FUSE User',
'collection #1 owned by FUSE'))
- self.assertEqual(st.st_mtime, 1391448174)
+ try:
+ mtime = st.st_mtime_ns / 1000000000
+ except AttributeError:
+ mtime = st.st_mtime
+ self.assertEqual(mtime, 1391448174)
class FuseHomeTest(MountTestBase):
q.put(mockedCurl)
q.put(pycurl.Curl())
q.put(pycurl.Curl())
- with mock.patch('arvados.keep.KeepClient.KeepService._get_user_agent', side_effect=lambda: q.get(block=None)):
+ with mock.patch('arvados.keep.KeepClient.KeepService._get_user_agent', side_effect=q.get_nowait):
self.pool_test(os.path.join(self.mnt, 'zzz'))
self.assertTrue(mockedCurl.perform.called)
@staticmethod
}
if len(errs) > 0 {
// Some other goroutine encountered an
- // error -- any futher effort here
+ // error -- any further effort here
// will be wasted.
return
}
Logger: s.logger(c),
}
s.stub.serveCurrentUserAdmin()
- s.stub.serveFooBarFileCollections()
+ collReqs := s.stub.serveFooBarFileCollections()
s.stub.serveFourDiskKeepServices()
s.stub.serveKeepstoreIndexFoo4Bar1()
trashReqs := s.stub.serveKeepstoreTrash()
var bal Balancer
_, err := bal.Run(s.config, opts)
c.Check(err, check.IsNil)
+ for _, req := range collReqs.reqs {
+ c.Check(req.Form.Get("include_trash"), check.Equals, "true")
+ }
c.Check(trashReqs.Count(), check.Equals, 0)
c.Check(pullReqs.Count(), check.Equals, 0)
stats := bal.getStatistics()
progress = func(_, _ int) {}
}
- expectCount, err := countCollections(c, arvados.ResourceListParams{})
+ expectCount, err := countCollections(c, arvados.ResourceListParams{
+ IncludeTrash: true,
+ })
if err != nil {
return err
}
limit = 1<<31 - 1
}
params := arvados.ResourceListParams{
- Limit: &limit,
- Order: "modified_at, uuid",
- Count: false,
- Select: []string{"uuid", "manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+ Limit: &limit,
+ Order: "modified_at, uuid",
+ Count: false,
+ Select: []string{"uuid", "unsigned_manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+ IncludeTrash: true,
}
var last arvados.Collection
var filterTime time.Time
}
progress(callCount, expectCount)
- if checkCount, err := countCollections(c, arvados.ResourceListParams{Filters: []arvados.Filter{{
- Attr: "modified_at",
- Operator: "<=",
- Operand: filterTime}}}); err != nil {
+ if checkCount, err := countCollections(c, arvados.ResourceListParams{
+ Filters: []arvados.Filter{{
+ Attr: "modified_at",
+ Operator: "<=",
+ Operand: filterTime}},
+ IncludeTrash: true,
+ }); err != nil {
return err
} else if callCount < checkCount {
return fmt.Errorf("Retrieved %d collections with modtime <= T=%q, but server now reports there are %d collections with modtime <= T", callCount, filterTime, checkCount)
[Service]
Type=simple
-ExecStart=/usr/bin/keep-balance -config /etc/arvados/keep-balance/keep-balance.yml -commit-pulls -commit-trash
+ExecStart=/usr/bin/keep-balance -commit-pulls -commit-trash
Restart=always
RestartSec=10s
"git.curoverse.com/arvados.git/sdk/go/config"
)
+const defaultConfigPath = "/etc/arvados/keep-balance/keep-balance.yml"
+
// Config specifies site configuration, like API credentials and the
// choice of which servers are to be balanced.
//
var config Config
var runOptions RunOptions
- configPath := flag.String("config", "",
+ configPath := flag.String("config", defaultConfigPath,
"`path` of JSON or YAML configuration file")
serviceListPath := flag.String("config.KeepServiceList", "",
"`path` of JSON or YAML file with list of keep services to balance, as given by \"arv keep_service list\" "+
flag.Usage = usage
flag.Parse()
- if *configPath == "" {
- log.Fatal("You must specify a config file (see `keep-balance -help`)")
- }
mustReadConfig(&config, *configPath)
if *serviceListPath != "" {
mustReadConfig(&config.KeepServiceList, *serviceListPath)
positions (according to the rendezvous hash algorithm) so clients find
them faster.
-Usage: keep-balance -config path/to/keep-balance.yml [options]
+Usage: keep-balance [options]
Options:
`)
if err := srv.Start(); err != nil {
log.Fatal(err)
}
- if _, err := daemon.SdNotify("READY=1"); err != nil {
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
log.Printf("Error notifying init daemon: %v", err)
}
log.Println("Listening at", srv.Addr)
if err != nil {
log.Fatalf("listen(%s): %s", cfg.Listen, err)
}
- if _, err := daemon.SdNotify("READY=1"); err != nil {
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
log.Printf("Error notifying init daemon: %v", err)
}
log.Println("Listening at", listener.Addr())
"fmt"
"io"
"io/ioutil"
- "log"
"net/http"
"os"
"regexp"
"time"
"git.curoverse.com/arvados.git/sdk/go/arvados"
+ log "github.com/Sirupsen/logrus"
"github.com/curoverse/azure-sdk-for-go/storage"
)
type AzureBlobVolume struct {
StorageAccountName string
StorageAccountKeyFile string
+ StorageBaseURL string // "" means default, "core.windows.net"
ContainerName string
AzureReplication int
ReadOnly bool
RequestTimeout arvados.Duration
azClient storage.Client
- bsClient storage.BlobStorageClient
+ bsClient *azureBlobClient
}
// Examples implements VolumeWithExamples.
AzureReplication: 3,
RequestTimeout: azureDefaultRequestTimeout,
},
+ &AzureBlobVolume{
+ StorageAccountName: "cn-account-name",
+ StorageAccountKeyFile: "/etc/azure_cn_storage_account_key.txt",
+ StorageBaseURL: "core.chinacloudapi.cn",
+ ContainerName: "cn-container-name",
+ AzureReplication: 3,
+ RequestTimeout: azureDefaultRequestTimeout,
+ },
}
}
if err != nil {
return err
}
- v.azClient, err = storage.NewBasicClient(v.StorageAccountName, accountKey)
+ if v.StorageBaseURL == "" {
+ v.StorageBaseURL = storage.DefaultBaseURL
+ }
+ v.azClient, err = storage.NewClient(v.StorageAccountName, accountKey, v.StorageBaseURL, storage.DefaultAPIVersion, true)
if err != nil {
return fmt.Errorf("creating Azure storage client: %s", err)
}
v.azClient.HTTPClient = &http.Client{
Timeout: time.Duration(v.RequestTimeout),
}
- v.bsClient = v.azClient.GetBlobService()
+ bs := v.azClient.GetBlobService()
+ v.bsClient = &azureBlobClient{
+ client: &bs,
+ }
ok, err := v.bsClient.ContainerExists(v.ContainerName)
if err != nil {
}
var deadline time.Time
haveDeadline := false
- size, err := v.get(loc, buf)
+ size, err := v.get(ctx, loc, buf)
for err == nil && size == 0 && loc != "d41d8cd98f00b204e9800998ecf8427e" {
// Seeing a brand new empty block probably means we're
// in a race with CreateBlob, which under the hood
} else if time.Now().After(deadline) {
break
}
- time.Sleep(azureWriteRacePollTime)
- size, err = v.get(loc, buf)
+ select {
+ case <-ctx.Done():
+ return 0, ctx.Err()
+ case <-time.After(azureWriteRacePollTime):
+ }
+ size, err = v.get(ctx, loc, buf)
}
if haveDeadline {
log.Printf("Race ended with size==%d", size)
return size, err
}
-func (v *AzureBlobVolume) get(loc string, buf []byte) (int, error) {
+func (v *AzureBlobVolume) get(ctx context.Context, loc string, buf []byte) (int, error) {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
expectSize := len(buf)
if azureMaxGetBytes < BlockSize {
// Unfortunately the handler doesn't tell us how long the blob
// We'll update this actualSize if/when we get the last piece.
actualSize := -1
pieces := (expectSize + azureMaxGetBytes - 1) / azureMaxGetBytes
- errors := make([]error, pieces)
+ errors := make(chan error, pieces)
var wg sync.WaitGroup
wg.Add(pieces)
for p := 0; p < pieces; p++ {
+ // Each goroutine retrieves one piece. If we hit an
+ // error, it is sent to the errors chan so get() can
+ // return it -- but only if the error happens before
+ // ctx is done. This way, if ctx is done before we hit
+ // any other error (e.g., requesting client has hung
+ // up), we return the original ctx.Err() instead of
+ // the secondary errors from the transfers that got
+ // interrupted as a result.
go func(p int) {
defer wg.Done()
startPos := p * azureMaxGetBytes
}
var rdr io.ReadCloser
var err error
- if startPos == 0 && endPos == expectSize {
- rdr, err = v.bsClient.GetBlob(v.ContainerName, loc)
- } else {
- rdr, err = v.bsClient.GetBlobRange(v.ContainerName, loc, fmt.Sprintf("%d-%d", startPos, endPos-1), nil)
+ gotRdr := make(chan struct{})
+ go func() {
+ defer close(gotRdr)
+ if startPos == 0 && endPos == expectSize {
+ rdr, err = v.bsClient.GetBlob(v.ContainerName, loc)
+ } else {
+ rdr, err = v.bsClient.GetBlobRange(v.ContainerName, loc, fmt.Sprintf("%d-%d", startPos, endPos-1), nil)
+ }
+ }()
+ select {
+ case <-ctx.Done():
+ go func() {
+ <-gotRdr
+ if err == nil {
+ rdr.Close()
+ }
+ }()
+ return
+ case <-gotRdr:
}
if err != nil {
- errors[p] = err
+ errors <- err
+ cancel()
return
}
- defer rdr.Close()
+ go func() {
+ // Close the reader when the client
+ // hangs up or another piece fails
+ // (possibly interrupting ReadFull())
+ // or when all pieces succeed and
+ // get() returns.
+ <-ctx.Done()
+ rdr.Close()
+ }()
n, err := io.ReadFull(rdr, buf[startPos:endPos])
if pieces == 1 && (err == io.ErrUnexpectedEOF || err == io.EOF) {
// If we don't know the actual size,
// and just tried reading 64 MiB, it's
// normal to encounter EOF.
} else if err != nil {
- errors[p] = err
+ if ctx.Err() == nil {
+ errors <- err
+ }
+ cancel()
+ return
}
if p == pieces-1 {
actualSize = startPos + n
}(p)
}
wg.Wait()
- for _, err := range errors {
- if err != nil {
- return 0, v.translateError(err)
- }
+ close(errors)
+ if len(errors) > 0 {
+ return 0, v.translateError(<-errors)
+ }
+ if ctx.Err() != nil {
+ return 0, ctx.Err()
}
return actualSize, nil
}
if trashed {
return os.ErrNotExist
}
- rdr, err := v.bsClient.GetBlob(v.ContainerName, loc)
+ var rdr io.ReadCloser
+ gotRdr := make(chan struct{})
+ go func() {
+ defer close(gotRdr)
+ rdr, err = v.bsClient.GetBlob(v.ContainerName, loc)
+ }()
+ select {
+ case <-ctx.Done():
+ go func() {
+ <-gotRdr
+ if err == nil {
+ rdr.Close()
+ }
+ }()
+ return ctx.Err()
+ case <-gotRdr:
+ }
if err != nil {
return v.translateError(err)
}
if v.ReadOnly {
return MethodDisabledError
}
- return v.bsClient.CreateBlockBlobFromReader(v.ContainerName, loc, uint64(len(block)), bytes.NewReader(block), nil)
+ // Send the block data through a pipe, so that (if we need to)
+ // we can close the pipe early and abandon our
+ // CreateBlockBlobFromReader() goroutine, without worrying
+ // about CreateBlockBlobFromReader() accessing our block
+ // buffer after we release it.
+ bufr, bufw := io.Pipe()
+ go func() {
+ io.Copy(bufw, bytes.NewReader(block))
+ bufw.Close()
+ }()
+ errChan := make(chan error)
+ go func() {
+ errChan <- v.bsClient.CreateBlockBlobFromReader(v.ContainerName, loc, uint64(len(block)), bufr, nil)
+ }()
+ select {
+ case <-ctx.Done():
+ theConfig.debugLogf("%s: taking CreateBlockBlobFromReader's input away: %s", v, ctx.Err())
+ // Our pipe might be stuck in Write(), waiting for
+ // io.Copy() to read. If so, un-stick it. This means
+ // CreateBlockBlobFromReader will get corrupt data,
+ // but that's OK: the size won't match, so the write
+ // will fail.
+ go io.Copy(ioutil.Discard, bufr)
+ // CloseWithError() will return once pending I/O is done.
+ bufw.CloseWithError(ctx.Err())
+ theConfig.debugLogf("%s: abandoning CreateBlockBlobFromReader goroutine", v)
+ return ctx.Err()
+ case err := <-errChan:
+ return err
+ }
}
// Touch updates the last-modified property of a block blob.
log.Printf("EmptyTrash stats for %v: Deleted %v bytes in %v blocks. Remaining in trash: %v bytes in %v blocks.", v.String(), bytesDeleted, blocksDeleted, bytesInTrash-bytesDeleted, blocksInTrash-blocksDeleted)
}
+
+// InternalStats returns bucket I/O and API call counters.
+func (v *AzureBlobVolume) InternalStats() interface{} {
+ return &v.bsClient.stats
+}
+
+type azureBlobStats struct {
+ statsTicker
+ Ops uint64
+ GetOps uint64
+ GetRangeOps uint64
+ GetMetadataOps uint64
+ GetPropertiesOps uint64
+ CreateOps uint64
+ SetMetadataOps uint64
+ DelOps uint64
+ ListOps uint64
+}
+
+func (s *azureBlobStats) TickErr(err error) {
+ if err == nil {
+ return
+ }
+ errType := fmt.Sprintf("%T", err)
+ if err, ok := err.(storage.AzureStorageServiceError); ok {
+ errType = errType + fmt.Sprintf(" %d (%s)", err.StatusCode, err.Code)
+ }
+ log.Printf("errType %T, err %s", err, err)
+ s.statsTicker.TickErr(err, errType)
+}
+
+// azureBlobClient wraps storage.BlobStorageClient in order to count
+// I/O and API usage stats.
+type azureBlobClient struct {
+ client *storage.BlobStorageClient
+ stats azureBlobStats
+}
+
+func (c *azureBlobClient) ContainerExists(cname string) (bool, error) {
+ c.stats.Tick(&c.stats.Ops)
+ ok, err := c.client.ContainerExists(cname)
+ c.stats.TickErr(err)
+ return ok, err
+}
+
+func (c *azureBlobClient) GetBlobMetadata(cname, bname string) (map[string]string, error) {
+ c.stats.Tick(&c.stats.Ops, &c.stats.GetMetadataOps)
+ m, err := c.client.GetBlobMetadata(cname, bname)
+ c.stats.TickErr(err)
+ return m, err
+}
+
+func (c *azureBlobClient) GetBlobProperties(cname, bname string) (*storage.BlobProperties, error) {
+ c.stats.Tick(&c.stats.Ops, &c.stats.GetPropertiesOps)
+ p, err := c.client.GetBlobProperties(cname, bname)
+ c.stats.TickErr(err)
+ return p, err
+}
+
+func (c *azureBlobClient) GetBlob(cname, bname string) (io.ReadCloser, error) {
+ c.stats.Tick(&c.stats.Ops, &c.stats.GetOps)
+ rdr, err := c.client.GetBlob(cname, bname)
+ c.stats.TickErr(err)
+ return NewCountingReader(rdr, c.stats.TickInBytes), err
+}
+
+func (c *azureBlobClient) GetBlobRange(cname, bname, byterange string, hdrs map[string]string) (io.ReadCloser, error) {
+ c.stats.Tick(&c.stats.Ops, &c.stats.GetRangeOps)
+ rdr, err := c.client.GetBlobRange(cname, bname, byterange, hdrs)
+ c.stats.TickErr(err)
+ return NewCountingReader(rdr, c.stats.TickInBytes), err
+}
+
+func (c *azureBlobClient) CreateBlockBlobFromReader(cname, bname string, size uint64, rdr io.Reader, hdrs map[string]string) error {
+ c.stats.Tick(&c.stats.Ops, &c.stats.CreateOps)
+ rdr = NewCountingReader(rdr, c.stats.TickOutBytes)
+ err := c.client.CreateBlockBlobFromReader(cname, bname, size, rdr, hdrs)
+ c.stats.TickErr(err)
+ return err
+}
+
+func (c *azureBlobClient) SetBlobMetadata(cname, bname string, m, hdrs map[string]string) error {
+ c.stats.Tick(&c.stats.Ops, &c.stats.SetMetadataOps)
+ err := c.client.SetBlobMetadata(cname, bname, m, hdrs)
+ c.stats.TickErr(err)
+ return err
+}
+
+func (c *azureBlobClient) ListBlobs(cname string, params storage.ListBlobsParameters) (storage.BlobListResponse, error) {
+ c.stats.Tick(&c.stats.Ops, &c.stats.ListOps)
+ resp, err := c.client.ListBlobs(cname, params)
+ c.stats.TickErr(err)
+ return resp, err
+}
+
+func (c *azureBlobClient) DeleteBlob(cname, bname string, hdrs map[string]string) error {
+ c.stats.Tick(&c.stats.Ops, &c.stats.DelOps)
+ err := c.client.DeleteBlob(cname, bname, hdrs)
+ c.stats.TickErr(err)
+ return err
+}
"context"
"crypto/md5"
"encoding/base64"
+ "encoding/json"
"encoding/xml"
"flag"
"fmt"
"io/ioutil"
- "log"
"math/rand"
"net"
"net/http"
"testing"
"time"
+ log "github.com/Sirupsen/logrus"
"github.com/curoverse/azure-sdk-for-go/storage"
+ check "gopkg.in/check.v1"
)
const (
- // The same fake credentials used by Microsoft's Azure emulator
- emulatorAccountName = "devstoreaccount1"
- emulatorAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
+ // This cannot be the fake account name "devstoreaccount1"
+ // used by Microsoft's Azure emulator: the Azure SDK
+ // recognizes that magic string and changes its behavior to
+ // cater to the Azure SDK's own test suite.
+ fakeAccountName = "fakeAccountName"
+ fakeAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
)
var azureTestContainer string
// Connect to stub instead of real Azure storage service
stubURLBase := strings.Split(azStub.URL, "://")[1]
var err error
- if azClient, err = storage.NewClient(emulatorAccountName, emulatorAccountKey, stubURLBase, storage.DefaultAPIVersion, false); err != nil {
+ if azClient, err = storage.NewClient(fakeAccountName, fakeAccountKey, stubURLBase, storage.DefaultAPIVersion, false); err != nil {
t.Fatal(err)
}
container = "fakecontainername"
}
}
+ bs := azClient.GetBlobService()
v := &AzureBlobVolume{
ContainerName: container,
ReadOnly: readonly,
AzureReplication: replication,
azClient: azClient,
- bsClient: azClient.GetBlobService(),
+ bsClient: &azureBlobClient{client: &bs},
}
return &TestableAzureBlobVolume{
}
}
+var _ = check.Suite(&StubbedAzureBlobSuite{})
+
+type StubbedAzureBlobSuite struct {
+ volume *TestableAzureBlobVolume
+ origHTTPTransport http.RoundTripper
+}
+
+func (s *StubbedAzureBlobSuite) SetUpTest(c *check.C) {
+ s.origHTTPTransport = http.DefaultTransport
+ http.DefaultTransport = &http.Transport{
+ Dial: (&azStubDialer{}).Dial,
+ }
+ azureWriteRaceInterval = time.Millisecond
+ azureWriteRacePollTime = time.Nanosecond
+
+ s.volume = NewTestableAzureBlobVolume(c, false, 3)
+}
+
+func (s *StubbedAzureBlobSuite) TearDownTest(c *check.C) {
+ s.volume.Teardown()
+ http.DefaultTransport = s.origHTTPTransport
+}
+
func TestAzureBlobVolumeWithGeneric(t *testing.T) {
defer func(t http.RoundTripper) {
http.DefaultTransport = t
}
gotHash := fmt.Sprintf("%x", md5.Sum(gotData))
if gotLen != size {
- t.Error("length mismatch: got %d != %d", gotLen, size)
+ t.Errorf("length mismatch: got %d != %d", gotLen, size)
}
if gotHash != hash {
- t.Error("hash mismatch: got %s != %s", gotHash, hash)
+ t.Errorf("hash mismatch: got %s != %s", gotHash, hash)
}
}
}
}
}
+func TestAzureBlobVolumeContextCancelGet(t *testing.T) {
+ testAzureBlobVolumeContextCancel(t, func(ctx context.Context, v *TestableAzureBlobVolume) error {
+ v.PutRaw(TestHash, TestBlock)
+ _, err := v.Get(ctx, TestHash, make([]byte, BlockSize))
+ return err
+ })
+}
+
+func TestAzureBlobVolumeContextCancelPut(t *testing.T) {
+ testAzureBlobVolumeContextCancel(t, func(ctx context.Context, v *TestableAzureBlobVolume) error {
+ return v.Put(ctx, TestHash, make([]byte, BlockSize))
+ })
+}
+
+func TestAzureBlobVolumeContextCancelCompare(t *testing.T) {
+ testAzureBlobVolumeContextCancel(t, func(ctx context.Context, v *TestableAzureBlobVolume) error {
+ v.PutRaw(TestHash, TestBlock)
+ return v.Compare(ctx, TestHash, TestBlock2)
+ })
+}
+
+func testAzureBlobVolumeContextCancel(t *testing.T, testFunc func(context.Context, *TestableAzureBlobVolume) error) {
+ defer func(t http.RoundTripper) {
+ http.DefaultTransport = t
+ }(http.DefaultTransport)
+ http.DefaultTransport = &http.Transport{
+ Dial: (&azStubDialer{}).Dial,
+ }
+
+ v := NewTestableAzureBlobVolume(t, false, 3)
+ defer v.Teardown()
+ v.azHandler.race = make(chan chan struct{})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ allDone := make(chan struct{})
+ go func() {
+ defer close(allDone)
+ err := testFunc(ctx, v)
+ if err != context.Canceled {
+ t.Errorf("got %T %q, expected %q", err, err, context.Canceled)
+ }
+ }()
+ releaseHandler := make(chan struct{})
+ select {
+ case <-allDone:
+ t.Error("testFunc finished without waiting for v.azHandler.race")
+ case <-time.After(10 * time.Second):
+ t.Error("timed out waiting to enter handler")
+ case v.azHandler.race <- releaseHandler:
+ }
+
+ cancel()
+
+ select {
+ case <-time.After(10 * time.Second):
+ t.Error("timed out waiting to cancel")
+ case <-allDone:
+ }
+
+ go func() {
+ <-releaseHandler
+ }()
+}
+
+func (s *StubbedAzureBlobSuite) TestStats(c *check.C) {
+ stats := func() string {
+ buf, err := json.Marshal(s.volume.InternalStats())
+ c.Check(err, check.IsNil)
+ return string(buf)
+ }
+
+ c.Check(stats(), check.Matches, `.*"Ops":0,.*`)
+ c.Check(stats(), check.Matches, `.*"Errors":0,.*`)
+
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ _, err := s.volume.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.NotNil)
+ c.Check(stats(), check.Matches, `.*"Ops":[^0],.*`)
+ c.Check(stats(), check.Matches, `.*"Errors":[^0],.*`)
+ c.Check(stats(), check.Matches, `.*"storage\.AzureStorageServiceError 404 \(404 Not Found\)":[^0].*`)
+ c.Check(stats(), check.Matches, `.*"InBytes":0,.*`)
+
+ err = s.volume.Put(context.Background(), loc, []byte("foo"))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"OutBytes":3,.*`)
+ c.Check(stats(), check.Matches, `.*"CreateOps":1,.*`)
+
+ _, err = s.volume.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.IsNil)
+ _, err = s.volume.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"InBytes":6,.*`)
+}
+
func (v *TestableAzureBlobVolume) PutRaw(locator string, data []byte) {
v.azHandler.PutRaw(v.ContainerName, locator, data)
}
package main
import (
- "log"
"sync"
"sync/atomic"
"time"
+
+ log "github.com/Sirupsen/logrus"
)
type bufferPool struct {
"encoding/json"
"fmt"
"io/ioutil"
- "log"
"strings"
"time"
"git.curoverse.com/arvados.git/sdk/go/arvados"
+ log "github.com/Sirupsen/logrus"
)
type Config struct {
Debug bool
Listen string
+ LogFormat string
+
PIDFile string
MaxBuffers int
var theConfig = DefaultConfig()
+const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+
// DefaultConfig returns the default configuration.
func DefaultConfig() *Config {
return &Config{
Listen: ":25107",
+ LogFormat: "json",
MaxBuffers: 128,
RequireSignatures: true,
BlobSignatureTTL: arvados.Duration(14 * 24 * time.Hour),
// fields, and before using the config.
func (cfg *Config) Start() error {
if cfg.Debug {
+ log.SetLevel(log.DebugLevel)
cfg.debugLogf = log.Printf
cfg.debugLogf("debugging enabled")
} else {
cfg.debugLogf = func(string, ...interface{}) {}
}
+ switch strings.ToLower(cfg.LogFormat) {
+ case "text":
+ log.SetFormatter(&log.TextFormatter{
+ FullTimestamp: true,
+ TimestampFormat: rfc3339NanoFixed,
+ })
+ case "json":
+ log.SetFormatter(&log.JSONFormatter{
+ TimestampFormat: rfc3339NanoFixed,
+ })
+ default:
+ return fmt.Errorf(`unsupported log format %q (try "text" or "json")`, cfg.LogFormat)
+ }
+
if cfg.MaxBuffers < 0 {
return fmt.Errorf("MaxBuffers must be greater than zero")
}
package main
import (
- "log"
+ log "github.com/Sirupsen/logrus"
)
func init() {
--- /dev/null
+package main
+
+import (
+ "io"
+)
+
+func NewCountingWriter(w io.Writer, f func(uint64)) io.WriteCloser {
+ return &countingReadWriter{
+ writer: w,
+ counter: f,
+ }
+}
+
+func NewCountingReader(r io.Reader, f func(uint64)) io.ReadCloser {
+ return &countingReadWriter{
+ reader: r,
+ counter: f,
+ }
+}
+
+type countingReadWriter struct {
+ reader io.Reader
+ writer io.Writer
+ counter func(uint64)
+}
+
+func (crw *countingReadWriter) Read(buf []byte) (int, error) {
+ n, err := crw.reader.Read(buf)
+ crw.counter(uint64(n))
+ return n, err
+}
+
+func (crw *countingReadWriter) Write(buf []byte) (int, error) {
+ n, err := crw.writer.Write(buf)
+ crw.counter(uint64(n))
+ return n, err
+}
+
+func (crw *countingReadWriter) Close() error {
+ if c, ok := crw.writer.(io.Closer); ok {
+ return c.Close()
+ }
+ return nil
+}
ok := make(chan struct{})
go func() {
req, _ := http.NewRequest("GET", fmt.Sprintf("/%s+%d", TestHash, len(TestBlock)), nil)
- (&LoggingRESTRouter{MakeRESTRouter()}).ServeHTTP(resp, req)
+ (&LoggingRESTRouter{router: MakeRESTRouter()}).ServeHTTP(resp, req)
ok <- struct{}{}
}()
"fmt"
"github.com/gorilla/mux"
"io"
- "log"
"net/http"
"os"
"regexp"
"strings"
"sync"
"time"
+
+ "git.curoverse.com/arvados.git/sdk/go/httpserver"
+ log "github.com/Sirupsen/logrus"
)
-// MakeRESTRouter returns a new mux.Router that forwards all Keep
-// requests to the appropriate handlers.
-//
-func MakeRESTRouter() *mux.Router {
+type router struct {
+ *mux.Router
+ limiter httpserver.RequestCounter
+}
+
+// MakeRESTRouter returns a new router that forwards all Keep requests
+// to the appropriate handlers.
+func MakeRESTRouter() *router {
rest := mux.NewRouter()
+ rtr := &router{Router: rest}
rest.HandleFunc(
`/{hash:[0-9a-f]{32}}`, GetBlockHandler).Methods("GET", "HEAD")
// Privileged client only.
rest.HandleFunc(`/index/{prefix:[0-9a-f]{0,32}}`, IndexHandler).Methods("GET", "HEAD")
+ // Internals/debugging info (runtime.MemStats)
+ rest.HandleFunc(`/debug.json`, rtr.DebugHandler).Methods("GET", "HEAD")
+
// List volumes: path, device number, bytes used/avail.
- rest.HandleFunc(`/status.json`, StatusHandler).Methods("GET", "HEAD")
+ rest.HandleFunc(`/status.json`, rtr.StatusHandler).Methods("GET", "HEAD")
// Replace the current pull queue.
rest.HandleFunc(`/pull`, PullHandler).Methods("PUT")
// 400 Bad Request.
rest.NotFoundHandler = http.HandlerFunc(BadRequestHandler)
- return rest
+ return rtr
}
// BadRequestHandler is a HandleFunc to address bad requests.
resp.Write([]byte{'\n'})
}
-// StatusHandler
-// Responds to /status.json requests with the current node status,
-// described in a JSON structure.
-//
-// The data given in a status.json response includes:
-// volumes - a list of Keep volumes currently in use by this server
-// each volume is an object with the following fields:
-// * mount_point
-// * device_num (an integer identifying the underlying filesystem)
-// * bytes_free
-// * bytes_used
-
// PoolStatus struct
type PoolStatus struct {
Alloc uint64 `json:"BytesAllocated"`
Len int `json:"BuffersInUse"`
}
+type volumeStatusEnt struct {
+ Label string
+ Status *VolumeStatus `json:",omitempty"`
+ VolumeStats *ioStats `json:",omitempty"`
+ InternalStats interface{} `json:",omitempty"`
+}
+
// NodeStatus struct
type NodeStatus struct {
- Volumes []*VolumeStatus `json:"volumes"`
- BufferPool PoolStatus
- PullQueue WorkQueueStatus
- TrashQueue WorkQueueStatus
- Memory runtime.MemStats
+ Volumes []*volumeStatusEnt
+ BufferPool PoolStatus
+ PullQueue WorkQueueStatus
+ TrashQueue WorkQueueStatus
+ RequestsCurrent int
+ RequestsMax int
}
var st NodeStatus
var stLock sync.Mutex
+// DebugHandler addresses /debug.json requests.
+func (rtr *router) DebugHandler(resp http.ResponseWriter, req *http.Request) {
+ type debugStats struct {
+ MemStats runtime.MemStats
+ }
+ var ds debugStats
+ runtime.ReadMemStats(&ds.MemStats)
+ err := json.NewEncoder(resp).Encode(&ds)
+ if err != nil {
+ http.Error(resp, err.Error(), 500)
+ }
+}
+
// StatusHandler addresses /status.json requests.
-func StatusHandler(resp http.ResponseWriter, req *http.Request) {
+func (rtr *router) StatusHandler(resp http.ResponseWriter, req *http.Request) {
stLock.Lock()
- readNodeStatus(&st)
+ rtr.readNodeStatus(&st)
jstat, err := json.Marshal(&st)
stLock.Unlock()
if err == nil {
}
// populate the given NodeStatus struct with current values.
-func readNodeStatus(st *NodeStatus) {
+func (rtr *router) readNodeStatus(st *NodeStatus) {
vols := KeepVM.AllReadable()
if cap(st.Volumes) < len(vols) {
- st.Volumes = make([]*VolumeStatus, len(vols))
+ st.Volumes = make([]*volumeStatusEnt, len(vols))
}
st.Volumes = st.Volumes[:0]
for _, vol := range vols {
- if s := vol.Status(); s != nil {
- st.Volumes = append(st.Volumes, s)
+ var internalStats interface{}
+ if vol, ok := vol.(InternalStatser); ok {
+ internalStats = vol.InternalStats()
}
+ st.Volumes = append(st.Volumes, &volumeStatusEnt{
+ Label: vol.String(),
+ Status: vol.Status(),
+ InternalStats: internalStats,
+ //VolumeStats: KeepVM.VolumeStats(vol),
+ })
}
st.BufferPool.Alloc = bufs.Alloc()
st.BufferPool.Cap = bufs.Cap()
st.BufferPool.Len = bufs.Len()
st.PullQueue = getWorkQueueStatus(pullq)
st.TrashQueue = getWorkQueueStatus(trashq)
- runtime.ReadMemStats(&st.Memory)
+ if rtr.limiter != nil {
+ st.RequestsCurrent = rtr.limiter.Current()
+ st.RequestsMax = rtr.limiter.Max()
+ }
}
// return a WorkQueueStatus for the given queue. If q is nil (which
import (
"flag"
"fmt"
- "log"
"net"
"net/http"
"os"
"git.curoverse.com/arvados.git/sdk/go/config"
"git.curoverse.com/arvados.git/sdk/go/httpserver"
"git.curoverse.com/arvados.git/sdk/go/keepclient"
+ log "github.com/Sirupsen/logrus"
"github.com/coreos/go-systemd/daemon"
"github.com/ghodss/yaml"
)
}
err = theConfig.Start()
+ if err != nil {
+ log.Fatal(err)
+ }
if pidfile := theConfig.PIDFile; pidfile != "" {
f, err := os.OpenFile(pidfile, os.O_RDWR|os.O_CREATE, 0777)
KeepVM = MakeRRVolumeManager(theConfig.Volumes)
// Middleware stack: logger, MaxRequests limiter, method handlers
- http.Handle("/", &LoggingRESTRouter{
- httpserver.NewRequestLimiter(theConfig.MaxRequests,
- MakeRESTRouter()),
- })
+ router := MakeRESTRouter()
+ limiter := httpserver.NewRequestLimiter(theConfig.MaxRequests, router)
+ router.limiter = limiter
+ http.Handle("/", &LoggingRESTRouter{router: limiter})
// Set up a TCP listener.
listener, err := net.Listen("tcp", theConfig.Listen)
signal.Notify(term, syscall.SIGTERM)
signal.Notify(term, syscall.SIGINT)
- if _, err := daemon.SdNotify("READY=1"); err != nil {
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
log.Printf("Error notifying init daemon: %v", err)
}
log.Println("listening at", listener.Addr())
// LoggingResponseWriter
import (
- "log"
+ "context"
"net/http"
"strings"
"time"
+
+ "git.curoverse.com/arvados.git/sdk/go/httpserver"
+ "git.curoverse.com/arvados.git/sdk/go/stats"
+ log "github.com/Sirupsen/logrus"
)
// LoggingResponseWriter has anonymous fields ResponseWriter and ResponseBody
// LoggingRESTRouter is used to add logging capabilities to mux.Router
type LoggingRESTRouter struct {
- router http.Handler
+ router http.Handler
+ idGenerator httpserver.IDGenerator
}
func (loggingRouter *LoggingRESTRouter) ServeHTTP(wrappedResp http.ResponseWriter, req *http.Request) {
- t0 := time.Now()
+ tStart := time.Now()
+
+ // Attach a requestID-aware logger to the request context.
+ lgr := log.WithField("RequestID", loggingRouter.idGenerator.Next())
+ ctx := context.WithValue(req.Context(), "logger", lgr)
+ req = req.WithContext(ctx)
+
+ lgr = lgr.WithFields(log.Fields{
+ "remoteAddr": req.RemoteAddr,
+ "reqForwardedFor": req.Header.Get("X-Forwarded-For"),
+ "reqMethod": req.Method,
+ "reqPath": req.URL.Path[1:],
+ "reqBytes": req.ContentLength,
+ })
+ lgr.Debug("request")
+
resp := LoggingResponseWriter{http.StatusOK, 0, wrappedResp, "", zeroTime}
loggingRouter.router.ServeHTTP(&resp, req)
+ tDone := time.Now()
+
statusText := http.StatusText(resp.Status)
if resp.Status >= 400 {
statusText = strings.Replace(resp.ResponseBody, "\n", "", -1)
}
- now := time.Now()
- tTotal := now.Sub(t0)
- tLatency := resp.sentHdr.Sub(t0)
- tResponse := now.Sub(resp.sentHdr)
- log.Printf("[%s] %s %s %d %.6fs %.6fs %.6fs %d %d \"%s\"", req.RemoteAddr, req.Method, req.URL.Path[1:], req.ContentLength, tTotal.Seconds(), tLatency.Seconds(), tResponse.Seconds(), resp.Status, resp.Length, statusText)
+ if resp.sentHdr == zeroTime {
+ // Nobody changed status or wrote any data, i.e., we
+ // returned a 200 response with no body.
+ resp.sentHdr = tDone
+ }
+ lgr.WithFields(log.Fields{
+ "timeTotal": stats.Duration(tDone.Sub(tStart)),
+ "timeToStatus": stats.Duration(resp.sentHdr.Sub(tStart)),
+ "timeWriteBody": stats.Duration(tDone.Sub(resp.sentHdr)),
+ "respStatusCode": resp.Status,
+ "respStatus": statusText,
+ "respBytes": resp.Length,
+ }).Info("response")
}
--- /dev/null
+package main
+
+import (
+ "bytes"
+ "context"
+ "io"
+ "io/ioutil"
+)
+
+// getWithPipe invokes getter and copies the resulting data into
+// buf. If ctx is done before all data is copied, getWithPipe closes
+// the pipe with an error, and returns early with an error.
+func getWithPipe(ctx context.Context, loc string, buf []byte, br BlockReader) (int, error) {
+ piper, pipew := io.Pipe()
+ go func() {
+ pipew.CloseWithError(br.ReadBlock(ctx, loc, pipew))
+ }()
+ done := make(chan struct{})
+ var size int
+ var err error
+ go func() {
+ size, err = io.ReadFull(piper, buf)
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
+ err = nil
+ }
+ close(done)
+ }()
+ select {
+ case <-ctx.Done():
+ piper.CloseWithError(ctx.Err())
+ return 0, ctx.Err()
+ case <-done:
+ piper.Close()
+ return size, err
+ }
+}
+
+// putWithPipe invokes putter with a new pipe, and and copies data
+// from buf into the pipe. If ctx is done before all data is copied,
+// putWithPipe closes the pipe with an error, and returns early with
+// an error.
+func putWithPipe(ctx context.Context, loc string, buf []byte, bw BlockWriter) error {
+ piper, pipew := io.Pipe()
+ copyErr := make(chan error)
+ go func() {
+ _, err := io.Copy(pipew, bytes.NewReader(buf))
+ copyErr <- err
+ close(copyErr)
+ }()
+
+ putErr := make(chan error, 1)
+ go func() {
+ putErr <- bw.WriteBlock(ctx, loc, piper)
+ close(putErr)
+ }()
+
+ var err error
+ select {
+ case err = <-copyErr:
+ case err = <-putErr:
+ case <-ctx.Done():
+ err = ctx.Err()
+ }
+
+ // Ensure io.Copy goroutine isn't blocked writing to pipew
+ // (otherwise, io.Copy is still using buf so it isn't safe to
+ // return). This can cause pipew to receive corrupt data if
+ // err came from copyErr or ctx.Done() before the copy
+ // finished. That's OK, though: in that case err != nil, and
+ // CloseWithErr(err) ensures putter() will get an error from
+ // piper.Read() before seeing EOF.
+ go pipew.CloseWithError(err)
+ go io.Copy(ioutil.Discard, piper)
+ <-copyErr
+
+ // Note: io.Copy() is finished now, but putter() might still
+ // be running. If we encounter an error before putter()
+ // returns, we return right away without waiting for putter().
+
+ if err != nil {
+ return err
+ }
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case err = <-putErr:
+ return err
+ }
+}
"git.curoverse.com/arvados.git/sdk/go/keepclient"
"io"
"io/ioutil"
- "log"
"time"
+
+ log "github.com/Sirupsen/logrus"
)
// RunPullWorker is used by Keepstore to initiate pull worker channel goroutine.
"fmt"
"io"
"io/ioutil"
- "log"
"net/http"
"os"
"regexp"
"git.curoverse.com/arvados.git/sdk/go/arvados"
"github.com/AdRoll/goamz/aws"
"github.com/AdRoll/goamz/s3"
+ log "github.com/Sirupsen/logrus"
)
const (
ReadOnly bool
UnsafeDelete bool
- bucket *s3.Bucket
+ bucket *s3bucket
startOnce sync.Once
}
client := s3.New(auth, region)
client.ConnectTimeout = time.Duration(v.ConnectTimeout)
client.ReadTimeout = time.Duration(v.ReadTimeout)
- v.bucket = &s3.Bucket{
- S3: client,
- Name: v.Bucket,
+ v.bucket = &s3bucket{
+ Bucket: &s3.Bucket{
+ S3: client,
+ Name: v.Bucket,
+ },
}
return nil
}
if err == nil || !os.IsNotExist(err) {
return
}
+
_, err = v.bucket.Head("recent/"+loc, nil)
err = v.translateError(err)
if err != nil {
err = os.ErrNotExist
return
}
+
rdr, err = v.bucket.GetReader(loc)
if err != nil {
log.Printf("warning: reading %s after successful fixRace: %s", loc, err)
func (v *S3Volume) IndexTo(prefix string, writer io.Writer) error {
// Use a merge sort to find matching sets of X and recent/X.
dataL := s3Lister{
- Bucket: v.bucket,
+ Bucket: v.bucket.Bucket,
Prefix: prefix,
PageSize: v.IndexPageSize,
}
recentL := s3Lister{
- Bucket: v.bucket,
+ Bucket: v.bucket.Bucket,
Prefix: "recent/" + prefix,
PageSize: v.IndexPageSize,
}
+ v.bucket.stats.Tick(&v.bucket.stats.Ops, &v.bucket.stats.ListOps)
+ v.bucket.stats.Tick(&v.bucket.stats.Ops, &v.bucket.stats.ListOps)
for data, recent := dataL.First(), recentL.First(); data != nil; data = dataL.Next() {
+ v.bucket.stats.Tick(&v.bucket.stats.Ops, &v.bucket.stats.ListOps)
if data.Key >= "g" {
// Conveniently, "recent/*" and "trash/*" are
// lexically greater than all hex-encoded data
for recent != nil {
if cmp := strings.Compare(recent.Key[7:], data.Key); cmp < 0 {
recent = recentL.Next()
+ v.bucket.stats.Tick(&v.bucket.stats.Ops, &v.bucket.stats.ListOps)
continue
} else if cmp == 0 {
stamp = recent
recent = recentL.Next()
+ v.bucket.stats.Tick(&v.bucket.stats.Ops, &v.bucket.stats.ListOps)
break
} else {
// recent/X marker is missing: we'll
if !s3UnsafeDelete {
return ErrS3TrashDisabled
}
- return v.bucket.Del(loc)
+ return v.translateError(v.bucket.Del(loc))
}
err := v.checkRaceWindow(loc)
if err != nil {
}
}
+// InternalStats returns bucket I/O and API call counters.
+func (v *S3Volume) InternalStats() interface{} {
+ return &v.bucket.stats
+}
+
// String implements fmt.Stringer.
func (v *S3Volume) String() string {
- return fmt.Sprintf("s3-bucket:%+q", v.bucket.Name)
+ return fmt.Sprintf("s3-bucket:%+q", v.Bucket)
}
// Writable returns false if all future Put, Mtime, and Delete calls
// Use a merge sort to find matching sets of trash/X and recent/X.
trashL := s3Lister{
- Bucket: v.bucket,
+ Bucket: v.bucket.Bucket,
Prefix: "trash/",
PageSize: v.IndexPageSize,
}
v.fixRace(loc)
v.Touch(loc)
continue
- } else if _, err := v.bucket.Head(loc, nil); os.IsNotExist(err) {
+ }
+ _, err := v.bucket.Head(loc, nil)
+ if os.IsNotExist(err) {
log.Printf("notice: %s: EmptyTrash: detected recent race for %q, calling fixRace", v, loc)
v.fixRace(loc)
continue
}
return
}
+
+// s3bucket wraps s3.bucket and counts I/O and API usage stats.
+type s3bucket struct {
+ *s3.Bucket
+ stats s3bucketStats
+}
+
+func (b *s3bucket) GetReader(path string) (io.ReadCloser, error) {
+ rdr, err := b.Bucket.GetReader(path)
+ b.stats.Tick(&b.stats.Ops, &b.stats.GetOps)
+ b.stats.TickErr(err)
+ return NewCountingReader(rdr, b.stats.TickInBytes), err
+}
+
+func (b *s3bucket) Head(path string, headers map[string][]string) (*http.Response, error) {
+ resp, err := b.Bucket.Head(path, headers)
+ b.stats.Tick(&b.stats.Ops, &b.stats.HeadOps)
+ b.stats.TickErr(err)
+ return resp, err
+}
+
+func (b *s3bucket) PutReader(path string, r io.Reader, length int64, contType string, perm s3.ACL, options s3.Options) error {
+ err := b.Bucket.PutReader(path, NewCountingReader(r, b.stats.TickOutBytes), length, contType, perm, options)
+ b.stats.Tick(&b.stats.Ops, &b.stats.PutOps)
+ b.stats.TickErr(err)
+ return err
+}
+
+func (b *s3bucket) Put(path string, data []byte, contType string, perm s3.ACL, options s3.Options) error {
+ err := b.Bucket.PutReader(path, NewCountingReader(bytes.NewBuffer(data), b.stats.TickOutBytes), int64(len(data)), contType, perm, options)
+ b.stats.Tick(&b.stats.Ops, &b.stats.PutOps)
+ b.stats.TickErr(err)
+ return err
+}
+
+func (b *s3bucket) Del(path string) error {
+ err := b.Bucket.Del(path)
+ b.stats.Tick(&b.stats.Ops, &b.stats.DelOps)
+ b.stats.TickErr(err)
+ return err
+}
+
+type s3bucketStats struct {
+ statsTicker
+ Ops uint64
+ GetOps uint64
+ PutOps uint64
+ HeadOps uint64
+ DelOps uint64
+ ListOps uint64
+}
+
+func (s *s3bucketStats) TickErr(err error) {
+ if err == nil {
+ return
+ }
+ errType := fmt.Sprintf("%T", err)
+ if err, ok := err.(*s3.Error); ok {
+ errType = errType + fmt.Sprintf(" %d %s", err.StatusCode, err.Code)
+ }
+ s.statsTicker.TickErr(err, errType)
+}
"bytes"
"context"
"crypto/md5"
+ "encoding/json"
"fmt"
"io/ioutil"
- "log"
+ "net/http"
+ "net/http/httptest"
"os"
"time"
"git.curoverse.com/arvados.git/sdk/go/arvados"
"github.com/AdRoll/goamz/s3"
"github.com/AdRoll/goamz/s3/s3test"
+ log "github.com/Sirupsen/logrus"
check "gopkg.in/check.v1"
)
}
}
+func (s *StubbedS3Suite) TestStats(c *check.C) {
+ v := s.newTestableVolume(c, 5*time.Minute, false, 2)
+ stats := func() string {
+ buf, err := json.Marshal(v.InternalStats())
+ c.Check(err, check.IsNil)
+ return string(buf)
+ }
+
+ c.Check(stats(), check.Matches, `.*"Ops":0,.*`)
+
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ _, err := v.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.NotNil)
+ c.Check(stats(), check.Matches, `.*"Ops":[^0],.*`)
+ c.Check(stats(), check.Matches, `.*"\*s3.Error 404 [^"]*":[^0].*`)
+ c.Check(stats(), check.Matches, `.*"InBytes":0,.*`)
+
+ err = v.Put(context.Background(), loc, []byte("foo"))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"OutBytes":3,.*`)
+ c.Check(stats(), check.Matches, `.*"PutOps":2,.*`)
+
+ _, err = v.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.IsNil)
+ _, err = v.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"InBytes":6,.*`)
+}
+
+type blockingHandler struct {
+ requested chan *http.Request
+ unblock chan struct{}
+}
+
+func (h *blockingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if h.requested != nil {
+ h.requested <- r
+ }
+ if h.unblock != nil {
+ <-h.unblock
+ }
+ http.Error(w, "nothing here", http.StatusNotFound)
+}
+
+func (s *StubbedS3Suite) TestGetContextCancel(c *check.C) {
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ buf := make([]byte, 3)
+
+ s.testContextCancel(c, func(ctx context.Context, v *TestableS3Volume) error {
+ _, err := v.Get(ctx, loc, buf)
+ return err
+ })
+}
+
+func (s *StubbedS3Suite) TestCompareContextCancel(c *check.C) {
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ buf := []byte("bar")
+
+ s.testContextCancel(c, func(ctx context.Context, v *TestableS3Volume) error {
+ return v.Compare(ctx, loc, buf)
+ })
+}
+
+func (s *StubbedS3Suite) TestPutContextCancel(c *check.C) {
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ buf := []byte("foo")
+
+ s.testContextCancel(c, func(ctx context.Context, v *TestableS3Volume) error {
+ return v.Put(ctx, loc, buf)
+ })
+}
+
+func (s *StubbedS3Suite) testContextCancel(c *check.C, testFunc func(context.Context, *TestableS3Volume) error) {
+ handler := &blockingHandler{}
+ srv := httptest.NewServer(handler)
+ defer srv.Close()
+
+ v := s.newTestableVolume(c, 5*time.Minute, false, 2)
+ vol := *v.S3Volume
+ vol.Endpoint = srv.URL
+ v = &TestableS3Volume{S3Volume: &vol}
+ v.Start()
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ handler.requested = make(chan *http.Request)
+ handler.unblock = make(chan struct{})
+ defer close(handler.unblock)
+
+ doneFunc := make(chan struct{})
+ go func() {
+ err := testFunc(ctx, v)
+ c.Check(err, check.Equals, context.Canceled)
+ close(doneFunc)
+ }()
+
+ timeout := time.After(10 * time.Second)
+
+ // Wait for the stub server to receive a request, meaning
+ // Get() is waiting for an s3 operation.
+ select {
+ case <-timeout:
+ c.Fatal("timed out waiting for test func to call our handler")
+ case <-doneFunc:
+ c.Fatal("test func finished without even calling our handler!")
+ case <-handler.requested:
+ }
+
+ cancel()
+
+ select {
+ case <-timeout:
+ c.Fatal("timed out")
+ case <-doneFunc:
+ }
+}
+
func (s *StubbedS3Suite) TestBackendStates(c *check.C) {
defer func(tl, bs arvados.Duration) {
theConfig.TrashLifetime = tl
srv, err := s3test.NewServer(&s3test.Config{Clock: clock})
c.Assert(err, check.IsNil)
- tmp, err := ioutil.TempFile("", "keepstore")
- c.Assert(err, check.IsNil)
- defer os.Remove(tmp.Name())
- _, err = tmp.Write([]byte("xxx\n"))
- c.Assert(err, check.IsNil)
- c.Assert(tmp.Close(), check.IsNil)
-
v := &TestableS3Volume{
S3Volume: &S3Volume{
Bucket: TestBucketName,
- AccessKeyFile: tmp.Name(),
- SecretKeyFile: tmp.Name(),
Endpoint: srv.URL(),
Region: "test-region-1",
LocationConstraint: true,
ReadOnly: readonly,
IndexPageSize: 1000,
},
+ c: c,
server: srv,
serverClock: clock,
}
- c.Assert(v.Start(), check.IsNil)
+ v.Start()
err = v.bucket.PutBucket(s3.ACL("private"))
c.Assert(err, check.IsNil)
return v
}
+func (v *TestableS3Volume) Start() error {
+ tmp, err := ioutil.TempFile("", "keepstore")
+ v.c.Assert(err, check.IsNil)
+ defer os.Remove(tmp.Name())
+ _, err = tmp.Write([]byte("xxx\n"))
+ v.c.Assert(err, check.IsNil)
+ v.c.Assert(tmp.Close(), check.IsNil)
+
+ v.S3Volume.AccessKeyFile = tmp.Name()
+ v.S3Volume.SecretKeyFile = tmp.Name()
+
+ v.c.Assert(v.S3Volume.Start(), check.IsNil)
+ return nil
+}
+
// PutRaw skips the ContentMD5 test
func (v *TestableS3Volume) PutRaw(loc string, block []byte) {
err := v.bucket.Put(loc, block, "application/octet-stream", s3ACL, s3.Options{})
--- /dev/null
+package main
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+type statsTicker struct {
+ Errors uint64
+ InBytes uint64
+ OutBytes uint64
+
+ ErrorCodes map[string]uint64 `json:",omitempty"`
+ lock sync.Mutex
+}
+
+// Tick increments each of the given counters by 1 using
+// atomic.AddUint64.
+func (s *statsTicker) Tick(counters ...*uint64) {
+ for _, counter := range counters {
+ atomic.AddUint64(counter, 1)
+ }
+}
+
+// TickErr increments the overall error counter, as well as the
+// ErrorCodes entry for the given errType. If err is nil, TickErr is a
+// no-op.
+func (s *statsTicker) TickErr(err error, errType string) {
+ if err == nil {
+ return
+ }
+ s.Tick(&s.Errors)
+
+ s.lock.Lock()
+ if s.ErrorCodes == nil {
+ s.ErrorCodes = make(map[string]uint64)
+ }
+ s.ErrorCodes[errType]++
+ s.lock.Unlock()
+}
+
+// TickInBytes increments the incoming byte counter by n.
+func (s *statsTicker) TickInBytes(n uint64) {
+ atomic.AddUint64(&s.InBytes, n)
+}
+
+// TickOutBytes increments the outgoing byte counter by n.
+func (s *statsTicker) TickOutBytes(n uint64) {
+ atomic.AddUint64(&s.OutBytes, n)
+}
import (
"errors"
- "log"
"time"
"git.curoverse.com/arvados.git/sdk/go/arvados"
+ log "github.com/Sirupsen/logrus"
)
// RunTrashWorker is used by Keepstore to initiate trash worker channel goroutine.
"address" is a host IP address or name and "port" is a port number
or name.
+LogFormat:
+
+ Format of request/response and error logs: "json" or "text".
+
PIDFile:
Path to write PID file during startup. This file is kept open and
"time"
)
+type BlockWriter interface {
+ // WriteBlock reads all data from r, writes it to a backing
+ // store as "loc", and returns the number of bytes written.
+ WriteBlock(ctx context.Context, loc string, r io.Reader) error
+}
+
+type BlockReader interface {
+ // ReadBlock retrieves data previously stored as "loc" and
+ // writes it to w.
+ ReadBlock(ctx context.Context, loc string, w io.Writer) error
+}
+
// A Volume is an interface representing a Keep back-end storage unit:
// for example, a single mounted disk, a RAID array, an Amazon S3 volume,
// etc.
// with more free space, etc.
NextWritable() Volume
+ // VolumeStats returns the ioStats used for tracking stats for
+ // the given Volume.
+ VolumeStats(Volume) *ioStats
+
// Close shuts down the volume manager cleanly.
Close()
}
readables []Volume
writables []Volume
counter uint32
+ iostats map[Volume]*ioStats
}
// MakeRRVolumeManager initializes RRVolumeManager
func MakeRRVolumeManager(volumes []Volume) *RRVolumeManager {
- vm := &RRVolumeManager{}
+ vm := &RRVolumeManager{
+ iostats: make(map[Volume]*ioStats),
+ }
for _, v := range volumes {
+ vm.iostats[v] = &ioStats{}
vm.readables = append(vm.readables, v)
if v.Writable() {
vm.writables = append(vm.writables, v)
return vm.writables[i%uint32(len(vm.writables))]
}
+// VolumeStats returns an ioStats for the given volume.
+func (vm *RRVolumeManager) VolumeStats(v Volume) *ioStats {
+ return vm.iostats[v]
+}
+
// Close the RRVolumeManager
func (vm *RRVolumeManager) Close() {
}
-// VolumeStatus provides status information of the volume consisting of:
-// * mount_point
-// * device_num (an integer identifying the underlying storage system)
-// * bytes_free
-// * bytes_used
+// VolumeStatus describes the current condition of a volume
type VolumeStatus struct {
- MountPoint string `json:"mount_point"`
- DeviceNum uint64 `json:"device_num"`
- BytesFree uint64 `json:"bytes_free"`
- BytesUsed uint64 `json:"bytes_used"`
+ MountPoint string
+ DeviceNum uint64
+ BytesFree uint64
+ BytesUsed uint64
+}
+
+// ioStats tracks I/O statistics for a volume or server
+type ioStats struct {
+ Errors uint64
+ Ops uint64
+ CompareOps uint64
+ GetOps uint64
+ PutOps uint64
+ TouchOps uint64
+ InBytes uint64
+ OutBytes uint64
+}
+
+type InternalStatser interface {
+ InternalStats() interface{}
}
"fmt"
"io"
"io/ioutil"
- "log"
"os"
"path/filepath"
"regexp"
"sync"
"syscall"
"time"
+
+ log "github.com/Sirupsen/logrus"
)
type unixVolumeAdder struct {
// something to lock during IO, typically a sync.Mutex (or nil
// to skip locking)
locker sync.Locker
+
+ os osWithStats
}
// Examples implements VolumeWithExamples.
if v.DirectoryReplication == 0 {
v.DirectoryReplication = 1
}
- _, err := os.Stat(v.Root)
+ _, err := v.os.Stat(v.Root)
return err
}
return MethodDisabledError
}
p := v.blockPath(loc)
- f, err := os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644)
+ f, err := v.os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644)
if err != nil {
return err
}
defer f.Close()
- if v.locker != nil {
- v.locker.Lock()
- defer v.locker.Unlock()
+ if err := v.lock(context.TODO()); err != nil {
+ return err
}
- if e := lockfile(f); e != nil {
+ defer v.unlock()
+ if e := v.lockfile(f); e != nil {
return e
}
- defer unlockfile(f)
+ defer v.unlockfile(f)
ts := syscall.NsecToTimespec(time.Now().UnixNano())
- return syscall.UtimesNano(p, []syscall.Timespec{ts, ts})
+ v.os.stats.Tick(&v.os.stats.UtimesOps)
+ err = syscall.UtimesNano(p, []syscall.Timespec{ts, ts})
+ v.os.stats.TickErr(err)
+ return err
}
// Mtime returns the stored timestamp for the given locator.
func (v *UnixVolume) Mtime(loc string) (time.Time, error) {
p := v.blockPath(loc)
- fi, err := os.Stat(p)
+ fi, err := v.os.Stat(p)
if err != nil {
return time.Time{}, err
}
// Lock the locker (if one is in use), open the file for reading, and
// call the given function if and when the file is ready to read.
func (v *UnixVolume) getFunc(ctx context.Context, path string, fn func(io.Reader) error) error {
- if v.locker != nil {
- v.locker.Lock()
- defer v.locker.Unlock()
- }
- if ctx.Err() != nil {
- return ctx.Err()
+ if err := v.lock(ctx); err != nil {
+ return err
}
- f, err := os.Open(path)
+ defer v.unlock()
+ f, err := v.os.Open(path)
if err != nil {
return err
}
defer f.Close()
- return fn(f)
+ return fn(NewCountingReader(ioutil.NopCloser(f), v.os.stats.TickInBytes))
}
// stat is os.Stat() with some extra sanity checks.
func (v *UnixVolume) stat(path string) (os.FileInfo, error) {
- stat, err := os.Stat(path)
+ stat, err := v.os.Stat(path)
if err == nil {
if stat.Size() < 0 {
err = os.ErrInvalid
// Get retrieves a block, copies it to the given slice, and returns
// the number of bytes copied.
func (v *UnixVolume) Get(ctx context.Context, loc string, buf []byte) (int, error) {
+ return getWithPipe(ctx, loc, buf, v)
+}
+
+// ReadBlock implements BlockReader.
+func (v *UnixVolume) ReadBlock(ctx context.Context, loc string, w io.Writer) error {
path := v.blockPath(loc)
stat, err := v.stat(path)
if err != nil {
- return 0, v.translateError(err)
- }
- if stat.Size() > int64(len(buf)) {
- return 0, TooLongError
+ return v.translateError(err)
}
- var read int
- size := int(stat.Size())
- err = v.getFunc(ctx, path, func(rdr io.Reader) error {
- read, err = io.ReadFull(rdr, buf[:size])
+ return v.getFunc(ctx, path, func(rdr io.Reader) error {
+ n, err := io.Copy(w, rdr)
+ if err == nil && n != stat.Size() {
+ err = io.ErrUnexpectedEOF
+ }
return err
})
- return read, err
}
// Compare returns nil if Get(loc) would return the same content as
// returns a FullError. If the write fails due to some other error,
// that error is returned.
func (v *UnixVolume) Put(ctx context.Context, loc string, block []byte) error {
+ return putWithPipe(ctx, loc, block, v)
+}
+
+// ReadBlock implements BlockWriter.
+func (v *UnixVolume) WriteBlock(ctx context.Context, loc string, rdr io.Reader) error {
if v.ReadOnly {
return MethodDisabledError
}
return err
}
- tmpfile, tmperr := ioutil.TempFile(bdir, "tmp"+loc)
+ tmpfile, tmperr := v.os.TempFile(bdir, "tmp"+loc)
if tmperr != nil {
log.Printf("ioutil.TempFile(%s, tmp%s): %s", bdir, loc, tmperr)
return tmperr
}
+
bpath := v.blockPath(loc)
- if v.locker != nil {
- v.locker.Lock()
- defer v.locker.Unlock()
- }
- select {
- case <-ctx.Done():
- return ctx.Err()
- default:
+ if err := v.lock(ctx); err != nil {
+ return err
}
- if _, err := tmpfile.Write(block); err != nil {
+ defer v.unlock()
+ n, err := io.Copy(tmpfile, rdr)
+ v.os.stats.TickOutBytes(uint64(n))
+ if err != nil {
log.Printf("%s: writing to %s: %s\n", v, bpath, err)
tmpfile.Close()
- os.Remove(tmpfile.Name())
+ v.os.Remove(tmpfile.Name())
return err
}
if err := tmpfile.Close(); err != nil {
log.Printf("closing %s: %s\n", tmpfile.Name(), err)
- os.Remove(tmpfile.Name())
+ v.os.Remove(tmpfile.Name())
return err
}
- if err := os.Rename(tmpfile.Name(), bpath); err != nil {
+ if err := v.os.Rename(tmpfile.Name(), bpath); err != nil {
log.Printf("rename %s %s: %s\n", tmpfile.Name(), bpath, err)
- os.Remove(tmpfile.Name())
- return err
+ return v.os.Remove(tmpfile.Name())
}
return nil
}
// current state, or nil if an error occurs.
//
func (v *UnixVolume) Status() *VolumeStatus {
- var fs syscall.Statfs_t
- var devnum uint64
-
- if fi, err := os.Stat(v.Root); err == nil {
- devnum = fi.Sys().(*syscall.Stat_t).Dev
- } else {
+ fi, err := v.os.Stat(v.Root)
+ if err != nil {
log.Printf("%s: os.Stat: %s\n", v, err)
return nil
}
+ devnum := fi.Sys().(*syscall.Stat_t).Dev
- err := syscall.Statfs(v.Root, &fs)
- if err != nil {
+ var fs syscall.Statfs_t
+ if err := syscall.Statfs(v.Root, &fs); err != nil {
log.Printf("%s: statfs: %s\n", v, err)
return nil
}
// uses fs.Blocks - fs.Bfree.
free := fs.Bavail * uint64(fs.Bsize)
used := (fs.Blocks - fs.Bfree) * uint64(fs.Bsize)
- return &VolumeStatus{v.Root, devnum, free, used}
+ return &VolumeStatus{
+ MountPoint: v.Root,
+ DeviceNum: devnum,
+ BytesFree: free,
+ BytesUsed: used,
+ }
}
var blockDirRe = regexp.MustCompile(`^[0-9a-f]+$`)
//
func (v *UnixVolume) IndexTo(prefix string, w io.Writer) error {
var lastErr error
- rootdir, err := os.Open(v.Root)
+ rootdir, err := v.os.Open(v.Root)
if err != nil {
return err
}
defer rootdir.Close()
+ v.os.stats.Tick(&v.os.stats.ReaddirOps)
for {
names, err := rootdir.Readdirnames(1)
if err == io.EOF {
continue
}
blockdirpath := filepath.Join(v.Root, names[0])
- blockdir, err := os.Open(blockdirpath)
+ blockdir, err := v.os.Open(blockdirpath)
if err != nil {
log.Print("Error reading ", blockdirpath, ": ", err)
lastErr = err
continue
}
+ v.os.stats.Tick(&v.os.stats.ReaddirOps)
for {
fileInfo, err := blockdir.Readdir(1)
if err == io.EOF {
if v.ReadOnly {
return MethodDisabledError
}
- if v.locker != nil {
- v.locker.Lock()
- defer v.locker.Unlock()
+ if err := v.lock(context.TODO()); err != nil {
+ return err
}
+ defer v.unlock()
p := v.blockPath(loc)
- f, err := os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644)
+ f, err := v.os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644)
if err != nil {
return err
}
defer f.Close()
- if e := lockfile(f); e != nil {
+ if e := v.lockfile(f); e != nil {
return e
}
- defer unlockfile(f)
+ defer v.unlockfile(f)
// If the block has been PUT in the last blobSignatureTTL
// seconds, return success without removing the block. This
// protects data from garbage collection until it is no longer
// possible for clients to retrieve the unreferenced blocks
// anyway (because the permission signatures have expired).
- if fi, err := os.Stat(p); err != nil {
+ if fi, err := v.os.Stat(p); err != nil {
return err
} else if time.Since(fi.ModTime()) < time.Duration(theConfig.BlobSignatureTTL) {
return nil
}
if theConfig.TrashLifetime == 0 {
- return os.Remove(p)
+ return v.os.Remove(p)
}
- return os.Rename(p, fmt.Sprintf("%v.trash.%d", p, time.Now().Add(theConfig.TrashLifetime.Duration()).Unix()))
+ return v.os.Rename(p, fmt.Sprintf("%v.trash.%d", p, time.Now().Add(theConfig.TrashLifetime.Duration()).Unix()))
}
// Untrash moves block from trash back into store
return MethodDisabledError
}
+ v.os.stats.Tick(&v.os.stats.ReaddirOps)
files, err := ioutil.ReadDir(v.blockDir(loc))
if err != nil {
return err
for _, f := range files {
if strings.HasPrefix(f.Name(), prefix) {
foundTrash = true
- err = os.Rename(v.blockPath(f.Name()), v.blockPath(loc))
+ err = v.os.Rename(v.blockPath(f.Name()), v.blockPath(loc))
if err == nil {
break
}
return v.DirectoryReplication
}
+// InternalStats returns I/O and filesystem ops counters.
+func (v *UnixVolume) InternalStats() interface{} {
+ return &v.os.stats
+}
+
+// lock acquires the serialize lock, if one is in use. If ctx is done
+// before the lock is acquired, lock returns ctx.Err() instead of
+// acquiring the lock.
+func (v *UnixVolume) lock(ctx context.Context) error {
+ if v.locker == nil {
+ return nil
+ }
+ locked := make(chan struct{})
+ go func() {
+ v.locker.Lock()
+ close(locked)
+ }()
+ select {
+ case <-ctx.Done():
+ go func() {
+ <-locked
+ v.locker.Unlock()
+ }()
+ return ctx.Err()
+ case <-locked:
+ return nil
+ }
+}
+
+// unlock releases the serialize lock, if one is in use.
+func (v *UnixVolume) unlock() {
+ if v.locker == nil {
+ return
+ }
+ v.locker.Unlock()
+}
+
// lockfile and unlockfile use flock(2) to manage kernel file locks.
-func lockfile(f *os.File) error {
- return syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
+func (v *UnixVolume) lockfile(f *os.File) error {
+ v.os.stats.Tick(&v.os.stats.FlockOps)
+ err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
+ v.os.stats.TickErr(err)
+ return err
}
-func unlockfile(f *os.File) error {
- return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
+func (v *UnixVolume) unlockfile(f *os.File) error {
+ err := syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
+ v.os.stats.TickErr(err)
+ return err
}
// Where appropriate, translate a more specific filesystem error to an
if deadline > time.Now().Unix() {
return nil
}
- err = os.Remove(path)
+ err = v.os.Remove(path)
if err != nil {
log.Printf("EmptyTrash: Remove %v: %v", path, err)
return nil
log.Printf("EmptyTrash stats for %v: Deleted %v bytes in %v blocks. Remaining in trash: %v bytes in %v blocks.", v.String(), bytesDeleted, blocksDeleted, bytesInTrash-bytesDeleted, blocksInTrash-blocksDeleted)
}
+
+type unixStats struct {
+ statsTicker
+ OpenOps uint64
+ StatOps uint64
+ FlockOps uint64
+ UtimesOps uint64
+ CreateOps uint64
+ RenameOps uint64
+ UnlinkOps uint64
+ ReaddirOps uint64
+}
+
+func (s *unixStats) TickErr(err error) {
+ if err == nil {
+ return
+ }
+ s.statsTicker.TickErr(err, fmt.Sprintf("%T", err))
+}
+
+type osWithStats struct {
+ stats unixStats
+}
+
+func (o *osWithStats) Open(name string) (*os.File, error) {
+ o.stats.Tick(&o.stats.OpenOps)
+ f, err := os.Open(name)
+ o.stats.TickErr(err)
+ return f, err
+}
+
+func (o *osWithStats) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+ o.stats.Tick(&o.stats.OpenOps)
+ f, err := os.OpenFile(name, flag, perm)
+ o.stats.TickErr(err)
+ return f, err
+}
+
+func (o *osWithStats) Remove(path string) error {
+ o.stats.Tick(&o.stats.UnlinkOps)
+ err := os.Remove(path)
+ o.stats.TickErr(err)
+ return err
+}
+
+func (o *osWithStats) Rename(a, b string) error {
+ o.stats.Tick(&o.stats.RenameOps)
+ err := os.Rename(a, b)
+ o.stats.TickErr(err)
+ return err
+}
+
+func (o *osWithStats) Stat(path string) (os.FileInfo, error) {
+ o.stats.Tick(&o.stats.StatOps)
+ fi, err := os.Stat(path)
+ o.stats.TickErr(err)
+ return fi, err
+}
+
+func (o *osWithStats) TempFile(dir, base string) (*os.File, error) {
+ o.stats.Tick(&o.stats.CreateOps)
+ f, err := ioutil.TempFile(dir, base)
+ o.stats.TickErr(err)
+ return f, err
+}
import (
"bytes"
"context"
+ "encoding/json"
"errors"
"fmt"
"io"
"syscall"
"testing"
"time"
+
+ check "gopkg.in/check.v1"
)
type TestableUnixVolume struct {
}
}
-// TODO(twp): show that the underlying Read/Write operations executed
-// serially and not concurrently. The easiest way to do this is
-// probably to activate verbose or debug logging, capture log output
-// and examine it to confirm that Reads and Writes did not overlap.
-//
-// TODO(twp): a proper test of I/O serialization requires that a
-// second request start while the first one is still underway.
-// Guaranteeing that the test behaves this way requires some tricky
-// synchronization and mocking. For now we'll just launch a bunch of
-// requests simultaenously in goroutines and demonstrate that they
-// return accurate results.
+func TestUnixVolumeContextCancelPut(t *testing.T) {
+ v := NewTestableUnixVolume(t, true, false)
+ defer v.Teardown()
+ v.locker.Lock()
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ time.Sleep(50 * time.Millisecond)
+ cancel()
+ time.Sleep(50 * time.Millisecond)
+ v.locker.Unlock()
+ }()
+ err := v.Put(ctx, TestHash, TestBlock)
+ if err != context.Canceled {
+ t.Errorf("Put() returned %s -- expected short read / canceled", err)
+ }
+}
+
+func TestUnixVolumeContextCancelGet(t *testing.T) {
+ v := NewTestableUnixVolume(t, false, false)
+ defer v.Teardown()
+ bpath := v.blockPath(TestHash)
+ v.PutRaw(TestHash, TestBlock)
+ os.Remove(bpath)
+ err := syscall.Mkfifo(bpath, 0600)
+ if err != nil {
+ t.Fatalf("Mkfifo %s: %s", bpath, err)
+ }
+ defer os.Remove(bpath)
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ time.Sleep(50 * time.Millisecond)
+ cancel()
+ }()
+ buf := make([]byte, len(TestBlock))
+ n, err := v.Get(ctx, TestHash, buf)
+ if n == len(TestBlock) || err != context.Canceled {
+ t.Errorf("Get() returned %d, %s -- expected short read / canceled", n, err)
+ }
+}
+
+var _ = check.Suite(&UnixVolumeSuite{})
+
+type UnixVolumeSuite struct {
+ volume *TestableUnixVolume
+}
+
+func (s *UnixVolumeSuite) TearDownTest(c *check.C) {
+ if s.volume != nil {
+ s.volume.Teardown()
+ }
+}
+
+func (s *UnixVolumeSuite) TestStats(c *check.C) {
+ s.volume = NewTestableUnixVolume(c, false, false)
+ stats := func() string {
+ buf, err := json.Marshal(s.volume.InternalStats())
+ c.Check(err, check.IsNil)
+ return string(buf)
+ }
+
+ c.Check(stats(), check.Matches, `.*"StatOps":0,.*`)
+ c.Check(stats(), check.Matches, `.*"Errors":0,.*`)
+
+ loc := "acbd18db4cc2f85cedef654fccc4a4d8"
+ _, err := s.volume.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.NotNil)
+ c.Check(stats(), check.Matches, `.*"StatOps":[^0],.*`)
+ c.Check(stats(), check.Matches, `.*"Errors":[^0],.*`)
+ c.Check(stats(), check.Matches, `.*"\*os\.PathError":[^0].*`)
+ c.Check(stats(), check.Matches, `.*"InBytes":0,.*`)
+ c.Check(stats(), check.Matches, `.*"OpenOps":0,.*`)
+ c.Check(stats(), check.Matches, `.*"CreateOps":0,.*`)
+
+ err = s.volume.Put(context.Background(), loc, []byte("foo"))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"OutBytes":3,.*`)
+ c.Check(stats(), check.Matches, `.*"CreateOps":1,.*`)
+ c.Check(stats(), check.Matches, `.*"OpenOps":0,.*`)
+ c.Check(stats(), check.Matches, `.*"UtimesOps":0,.*`)
+
+ err = s.volume.Touch(loc)
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"FlockOps":1,.*`)
+ c.Check(stats(), check.Matches, `.*"OpenOps":1,.*`)
+ c.Check(stats(), check.Matches, `.*"UtimesOps":1,.*`)
+
+ _, err = s.volume.Get(context.Background(), loc, make([]byte, 3))
+ c.Check(err, check.IsNil)
+ err = s.volume.Compare(context.Background(), loc, []byte("foo"))
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"InBytes":6,.*`)
+ c.Check(stats(), check.Matches, `.*"OpenOps":3,.*`)
+
+ err = s.volume.Trash(loc)
+ c.Check(err, check.IsNil)
+ c.Check(stats(), check.Matches, `.*"FlockOps":2,.*`)
+}
--- /dev/null
+import pkg_resources
+
+__version__ = pkg_resources.require('arvados-node-manager')[0].version
create_kwargs = create_kwargs.copy()
create_kwargs.setdefault('external_ip', None)
create_kwargs.setdefault('ex_metadata', {})
+ self._project = auth_kwargs.get("project")
super(ComputeNodeDriver, self).__init__(
auth_kwargs, list_kwargs, create_kwargs,
driver_class)
def _init_image(self, image_name):
return 'image', self.search_for(
- image_name, 'list_images', self._name_key)
+ image_name, 'list_images', self._name_key, ex_project=self._project)
def _init_network(self, network_name):
return 'ex_network', self.search_for(
import daemon
import pykka
+import libcloud
from . import config as nmconfig
from .baseactor import WatchdogActor
from .jobqueue import JobQueueMonitorActor, ServerCalculator
from .nodelist import ArvadosNodeListMonitorActor, CloudNodeListMonitorActor
from .timedcallback import TimedCallBackActor
+from ._version import __version__
node_daemon = None
parser = argparse.ArgumentParser(
prog='arvados-node-manager',
description="Dynamically allocate Arvados cloud compute nodes")
+ parser.add_argument(
+ '--version', action='version',
+ version="%s %s" % (sys.argv[0], __version__),
+ help='Print version and exit.')
parser.add_argument(
'--foreground', action='store_true', default=False,
help="Run in the foreground. Don't daemonize.")
for logger_name, sublevel in sublevels.iteritems():
sublogger = logging.getLogger(logger_name)
sublogger.setLevel(sublevel)
+ return root_logger
def build_server_calculator(config):
cloud_size_list = config.node_sizes(config.new_cloud_client().list_sizes())
signal.signal(sigcode, shutdown_signal)
try:
- setup_logging(config.get('Logging', 'file'), **config.log_levels())
+ root_logger = setup_logging(config.get('Logging', 'file'), **config.log_levels())
+ root_logger.info("%s %s, libcloud %s", sys.argv[0], __version__, libcloud.__version__)
node_setup, node_shutdown, node_update, node_monitor = \
config.dispatch_classes()
server_calculator = build_server_calculator(config)
'arvados-python-client>=0.1.20150206225333',
'pykka',
'python-daemon',
+ 'setuptools'
],
dependency_links = [
"https://github.com/curoverse/libcloud/archive/apache-libcloud-0.18.1.dev4.zip"
--- /dev/null
+#!/usr/bin/env python
+
+import io
+import os
+import sys
+import tempfile
+import unittest
+
+import arvnodeman.launcher as nodeman
+from . import testutil
+
+class ArvNodemArgumentsTestCase(unittest.TestCase):
+ def run_nodeman(self, args):
+ return nodeman.main(args)
+
+ def test_unsupported_arg(self):
+ with self.assertRaises(SystemExit):
+ self.run_nodeman(['-x=unknown'])
+
+ def test_version_argument(self):
+ err = io.BytesIO()
+ out = io.BytesIO()
+ with testutil.redirected_streams(stdout=out, stderr=err):
+ with self.assertRaises(SystemExit):
+ self.run_nodeman(['--version'])
+ self.assertEqual(out.getvalue(), '')
+ self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
from __future__ import absolute_import, print_function
+import contextlib
import datetime
+import mock
+import pykka
+import sys
import threading
import time
import libcloud.common.types as cloud_types
-import mock
-import pykka
from . import pykka_timeout
def ip_address_mock(last_octet):
return '10.20.30.{}'.format(last_octet)
+@contextlib.contextmanager
+def redirected_streams(stdout=None, stderr=None):
+ orig_stdout, sys.stdout = sys.stdout, stdout or sys.stdout
+ orig_stderr, sys.stderr = sys.stderr, stderr or sys.stderr
+ try:
+ yield
+ finally:
+ sys.stdout = orig_stdout
+ sys.stderr = orig_stderr
+
+
class MockShutdownTimer(object):
def _set_state(self, is_open, next_opening):
self.window_open = lambda: is_open
--- /dev/null
+[Unit]
+Description=Arvados websocket server
+Documentation=https://doc.arvados.org/
+After=network.target
+AssertPathExists=/etc/arvados/ws/ws.yml
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/arvados-ws
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+package main
+
+import (
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+)
+
+type wsConfig struct {
+ Client arvados.Client
+ Postgres pgConfig
+ Listen string
+ LogLevel string
+ LogFormat string
+
+ PingTimeout arvados.Duration
+ ClientEventQueue int
+ ServerEventQueue int
+}
+
+func defaultConfig() wsConfig {
+ return wsConfig{
+ Client: arvados.Client{
+ APIHost: "localhost:443",
+ },
+ Postgres: pgConfig{
+ "dbname": "arvados_production",
+ "user": "arvados",
+ "password": "xyzzy",
+ "host": "localhost",
+ "connect_timeout": "30",
+ "sslmode": "require",
+ },
+ LogLevel: "info",
+ LogFormat: "json",
+ PingTimeout: arvados.Duration(time.Minute),
+ ClientEventQueue: 64,
+ ServerEventQueue: 4,
+ }
+}
--- /dev/null
+// Arvados-ws exposes Arvados APIs (currently just one, the
+// cache-invalidation event feed at "ws://.../websocket") to
+// websocket clients.
+//
+// Installation
+//
+// See https://doc.arvados.org/install/install-ws.html.
+//
+// Developer info
+//
+// See https://dev.arvados.org/projects/arvados/wiki/Hacking_websocket_server.
+//
+// Usage
+//
+// arvados-ws [-config /etc/arvados/ws/ws.yml] [-dump-config]
+//
+// Minimal configuration
+//
+// Client:
+// APIHost: localhost:443
+// Listen: ":1234"
+// Postgres:
+// dbname: arvados_production
+// host: localhost
+// password: xyzzy
+// user: arvados
+//
+// Options
+//
+// -config path
+//
+// Load configuration from the given file instead of the default
+// /etc/arvados/ws/ws.yml
+//
+// -dump-config
+//
+// Print the loaded configuration to stdout and exit.
+//
+// Logs
+//
+// Logs are printed to stderr, formatted as JSON.
+//
+// A log is printed each time a client connects or disconnects.
+//
+// Enable additional logs by configuring:
+//
+// LogLevel: debug
+//
+// Runtime status
+//
+// GET /debug.json responds with debug stats.
+//
+// GET /status.json responds with health check results and
+// activity/usage metrics.
+package main
--- /dev/null
+package main
+
+import (
+ "database/sql"
+ "sync"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "github.com/ghodss/yaml"
+)
+
+type eventSink interface {
+ Channel() <-chan *event
+ Stop()
+}
+
+type eventSource interface {
+ NewSink() eventSink
+ DB() *sql.DB
+}
+
+type event struct {
+ LogID uint64
+ Received time.Time
+ Ready time.Time
+ Serial uint64
+
+ db *sql.DB
+ logRow *arvados.Log
+ err error
+ mtx sync.Mutex
+}
+
+// Detail returns the database row corresponding to the event. It can
+// be called safely from multiple goroutines. Only one attempt will be
+// made. If the database row cannot be retrieved, Detail returns nil.
+func (e *event) Detail() *arvados.Log {
+ e.mtx.Lock()
+ defer e.mtx.Unlock()
+ if e.logRow != nil || e.err != nil {
+ return e.logRow
+ }
+ var logRow arvados.Log
+ var propYAML []byte
+ e.err = e.db.QueryRow(`SELECT id, uuid, object_uuid, COALESCE(object_owner_uuid,''), COALESCE(event_type,''), event_at, created_at, properties FROM logs WHERE id = $1`, e.LogID).Scan(
+ &logRow.ID,
+ &logRow.UUID,
+ &logRow.ObjectUUID,
+ &logRow.ObjectOwnerUUID,
+ &logRow.EventType,
+ &logRow.EventAt,
+ &logRow.CreatedAt,
+ &propYAML)
+ if e.err != nil {
+ logger(nil).WithField("LogID", e.LogID).WithError(e.err).Error("QueryRow failed")
+ return nil
+ }
+ e.err = yaml.Unmarshal(propYAML, &logRow.Properties)
+ if e.err != nil {
+ logger(nil).WithField("LogID", e.LogID).WithError(e.err).Error("yaml decode failed")
+ return nil
+ }
+ e.logRow = &logRow
+ return e.logRow
+}
--- /dev/null
+package main
+
+import (
+ "database/sql"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/stats"
+ "github.com/lib/pq"
+)
+
+type pgConfig map[string]string
+
+func (c pgConfig) ConnectionString() string {
+ s := ""
+ for k, v := range c {
+ s += k
+ s += "='"
+ s += strings.Replace(
+ strings.Replace(v, `\`, `\\`, -1),
+ `'`, `\'`, -1)
+ s += "' "
+ }
+ return s
+}
+
+type pgEventSource struct {
+ DataSource string
+ QueueSize int
+
+ db *sql.DB
+ pqListener *pq.Listener
+ queue chan *event
+ sinks map[*pgEventSink]bool
+ setupOnce sync.Once
+ mtx sync.Mutex
+ shutdown chan error
+
+ lastQDelay time.Duration
+ eventsIn uint64
+ eventsOut uint64
+}
+
+var _ debugStatuser = (*pgEventSource)(nil)
+
+func (ps *pgEventSource) setup() {
+ ps.shutdown = make(chan error, 1)
+ ps.sinks = make(map[*pgEventSink]bool)
+
+ db, err := sql.Open("postgres", ps.DataSource)
+ if err != nil {
+ logger(nil).WithError(err).Fatal("sql.Open failed")
+ }
+ if err = db.Ping(); err != nil {
+ logger(nil).WithError(err).Fatal("db.Ping failed")
+ }
+ ps.db = db
+
+ ps.pqListener = pq.NewListener(ps.DataSource, time.Second, time.Minute, func(ev pq.ListenerEventType, err error) {
+ if err != nil {
+ // Until we have a mechanism for catching up
+ // on missed events, we cannot recover from a
+ // dropped connection without breaking our
+ // promises to clients.
+ logger(nil).WithError(err).Error("listener problem")
+ ps.shutdown <- err
+ }
+ })
+ err = ps.pqListener.Listen("logs")
+ if err != nil {
+ logger(nil).WithError(err).Fatal("pq Listen failed")
+ }
+ logger(nil).Debug("pgEventSource listening")
+
+ go ps.run()
+}
+
+func (ps *pgEventSource) run() {
+ ps.queue = make(chan *event, ps.QueueSize)
+
+ go func() {
+ for e := range ps.queue {
+ // Wait for the "select ... from logs" call to
+ // finish. This limits max concurrent queries
+ // to ps.QueueSize. Without this, max
+ // concurrent queries would be bounded by
+ // client_count X client_queue_size.
+ e.Detail()
+
+ logger(nil).
+ WithField("serial", e.Serial).
+ WithField("detail", e.Detail()).
+ Debug("event ready")
+ e.Ready = time.Now()
+ ps.lastQDelay = e.Ready.Sub(e.Received)
+
+ ps.mtx.Lock()
+ atomic.AddUint64(&ps.eventsOut, uint64(len(ps.sinks)))
+ for sink := range ps.sinks {
+ sink.channel <- e
+ }
+ ps.mtx.Unlock()
+ }
+ }()
+
+ var serial uint64
+ ticker := time.NewTicker(time.Minute)
+ defer ticker.Stop()
+ for {
+ select {
+ case err, ok := <-ps.shutdown:
+ if ok {
+ logger(nil).WithError(err).Info("shutdown")
+ }
+ close(ps.queue)
+ return
+
+ case <-ticker.C:
+ logger(nil).Debug("listener ping")
+ ps.pqListener.Ping()
+
+ case pqEvent, ok := <-ps.pqListener.Notify:
+ if !ok {
+ close(ps.queue)
+ return
+ }
+ if pqEvent.Channel != "logs" {
+ continue
+ }
+ logID, err := strconv.ParseUint(pqEvent.Extra, 10, 64)
+ if err != nil {
+ logger(nil).WithField("pqEvent", pqEvent).Error("bad notify payload")
+ continue
+ }
+ serial++
+ e := &event{
+ LogID: logID,
+ Received: time.Now(),
+ Serial: serial,
+ db: ps.db,
+ }
+ logger(nil).WithField("event", e).Debug("incoming")
+ atomic.AddUint64(&ps.eventsIn, 1)
+ ps.queue <- e
+ go e.Detail()
+ }
+ }
+}
+
+// NewSink subscribes to the event source. NewSink returns an
+// eventSink, whose Channel() method returns a channel: a pointer to
+// each subsequent event will be sent to that channel.
+//
+// The caller must ensure events are received from the sink channel as
+// quickly as possible because when one sink stops being ready, all
+// other sinks block.
+func (ps *pgEventSource) NewSink() eventSink {
+ ps.setupOnce.Do(ps.setup)
+ sink := &pgEventSink{
+ channel: make(chan *event, 1),
+ source: ps,
+ }
+ ps.mtx.Lock()
+ ps.sinks[sink] = true
+ ps.mtx.Unlock()
+ return sink
+}
+
+func (ps *pgEventSource) DB() *sql.DB {
+ ps.setupOnce.Do(ps.setup)
+ return ps.db
+}
+
+func (ps *pgEventSource) DebugStatus() interface{} {
+ ps.mtx.Lock()
+ defer ps.mtx.Unlock()
+ blocked := 0
+ for sink := range ps.sinks {
+ blocked += len(sink.channel)
+ }
+ return map[string]interface{}{
+ "EventsIn": atomic.LoadUint64(&ps.eventsIn),
+ "EventsOut": atomic.LoadUint64(&ps.eventsOut),
+ "Queue": len(ps.queue),
+ "QueueLimit": cap(ps.queue),
+ "QueueDelay": stats.Duration(ps.lastQDelay),
+ "Sinks": len(ps.sinks),
+ "SinksBlocked": blocked,
+ }
+}
+
+type pgEventSink struct {
+ channel chan *event
+ source *pgEventSource
+}
+
+func (sink *pgEventSink) Channel() <-chan *event {
+ return sink.channel
+}
+
+func (sink *pgEventSink) Stop() {
+ go func() {
+ // Ensure this sink cannot fill up and block the
+ // server-side queue (which otherwise could in turn
+ // block our mtx.Lock() here)
+ for _ = range sink.channel {
+ }
+ }()
+ sink.source.mtx.Lock()
+ delete(sink.source.sinks, sink)
+ sink.source.mtx.Unlock()
+ close(sink.channel)
+}
--- /dev/null
+package main
+
+import (
+ "context"
+ "io"
+ "sync"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "git.curoverse.com/arvados.git/sdk/go/stats"
+)
+
+type handler struct {
+ Client arvados.Client
+ PingTimeout time.Duration
+ QueueSize int
+
+ mtx sync.Mutex
+ lastDelay map[chan interface{}]stats.Duration
+ setupOnce sync.Once
+}
+
+type handlerStats struct {
+ QueueDelayNs time.Duration
+ WriteDelayNs time.Duration
+ EventBytes uint64
+ EventCount uint64
+}
+
+func (h *handler) Handle(ws wsConn, eventSource eventSource, newSession func(wsConn, chan<- interface{}) (session, error)) (hStats handlerStats) {
+ h.setupOnce.Do(h.setup)
+
+ ctx, cancel := context.WithCancel(ws.Request().Context())
+ defer cancel()
+ log := logger(ctx)
+
+ incoming := eventSource.NewSink()
+ defer incoming.Stop()
+
+ queue := make(chan interface{}, h.QueueSize)
+ h.mtx.Lock()
+ h.lastDelay[queue] = 0
+ h.mtx.Unlock()
+ defer func() {
+ h.mtx.Lock()
+ delete(h.lastDelay, queue)
+ h.mtx.Unlock()
+ }()
+
+ sess, err := newSession(ws, queue)
+ if err != nil {
+ log.WithError(err).Error("newSession failed")
+ return
+ }
+
+ // Receive websocket frames from the client and pass them to
+ // sess.Receive().
+ go func() {
+ buf := make([]byte, 2<<20)
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ default:
+ }
+ ws.SetReadDeadline(time.Now().Add(24 * 365 * time.Hour))
+ n, err := ws.Read(buf)
+ buf := buf[:n]
+ log.WithField("frame", string(buf[:n])).Debug("received frame")
+ if err == nil && n == cap(buf) {
+ err = errFrameTooBig
+ }
+ if err != nil {
+ if err != io.EOF {
+ log.WithError(err).Info("read error")
+ }
+ cancel()
+ return
+ }
+ err = sess.Receive(buf)
+ if err != nil {
+ log.WithError(err).Error("sess.Receive() failed")
+ cancel()
+ return
+ }
+ }
+ }()
+
+ // Take items from the outgoing queue, serialize them using
+ // sess.EventMessage() as needed, and send them to the client
+ // as websocket frames.
+ go func() {
+ for {
+ var ok bool
+ var data interface{}
+ select {
+ case <-ctx.Done():
+ return
+ case data, ok = <-queue:
+ if !ok {
+ return
+ }
+ }
+ var e *event
+ var buf []byte
+ var err error
+ log := log
+
+ switch data := data.(type) {
+ case []byte:
+ buf = data
+ case *event:
+ e = data
+ log = log.WithField("serial", e.Serial)
+ buf, err = sess.EventMessage(e)
+ if err != nil {
+ log.WithError(err).Error("EventMessage failed")
+ cancel()
+ break
+ } else if len(buf) == 0 {
+ log.Debug("skip")
+ continue
+ }
+ default:
+ log.WithField("data", data).Error("bad object in client queue")
+ continue
+ }
+
+ log.WithField("frame", string(buf)).Debug("send event")
+ ws.SetWriteDeadline(time.Now().Add(h.PingTimeout))
+ t0 := time.Now()
+ _, err = ws.Write(buf)
+ if err != nil {
+ log.WithError(err).Error("write failed")
+ cancel()
+ break
+ }
+ log.Debug("sent")
+
+ if e != nil {
+ hStats.QueueDelayNs += t0.Sub(e.Ready)
+ h.mtx.Lock()
+ h.lastDelay[queue] = stats.Duration(time.Since(e.Ready))
+ h.mtx.Unlock()
+ }
+ hStats.WriteDelayNs += time.Since(t0)
+ hStats.EventBytes += uint64(len(buf))
+ hStats.EventCount++
+ }
+ }()
+
+ // Filter incoming events against the current subscription
+ // list, and forward matching events to the outgoing message
+ // queue. Close the queue and return when the request context
+ // is done/cancelled or the incoming event stream ends. Shut
+ // down the handler if the outgoing queue fills up.
+ go func() {
+ ticker := time.NewTicker(h.PingTimeout)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-ticker.C:
+ // If the outgoing queue is empty,
+ // send an empty message. This can
+ // help detect a disconnected network
+ // socket, and prevent an idle socket
+ // from being closed.
+ if len(queue) == 0 {
+ select {
+ case queue <- []byte(`{}`):
+ default:
+ }
+ }
+ continue
+ case e, ok := <-incoming.Channel():
+ if !ok {
+ cancel()
+ return
+ }
+ if !sess.Filter(e) {
+ continue
+ }
+ select {
+ case queue <- e:
+ default:
+ log.WithError(errQueueFull).Error("terminate")
+ cancel()
+ return
+ }
+ }
+ }
+ }()
+
+ <-ctx.Done()
+ return
+}
+
+func (h *handler) DebugStatus() interface{} {
+ h.mtx.Lock()
+ defer h.mtx.Unlock()
+
+ var s struct {
+ QueueCount int
+ QueueMin int
+ QueueMax int
+ QueueTotal uint64
+ QueueDelayMin stats.Duration
+ QueueDelayMax stats.Duration
+ }
+ for q, lastDelay := range h.lastDelay {
+ s.QueueCount++
+ n := len(q)
+ s.QueueTotal += uint64(n)
+ if s.QueueMax < n {
+ s.QueueMax = n
+ }
+ if s.QueueMin > n || s.QueueCount == 1 {
+ s.QueueMin = n
+ }
+ if (s.QueueDelayMin > lastDelay || s.QueueDelayMin == 0) && lastDelay > 0 {
+ s.QueueDelayMin = lastDelay
+ }
+ if s.QueueDelayMax < lastDelay {
+ s.QueueDelayMax = lastDelay
+ }
+ }
+ return &s
+}
+
+func (h *handler) setup() {
+ h.lastDelay = make(map[chan interface{}]stats.Duration)
+}
--- /dev/null
+package main
+
+import (
+ "flag"
+ "fmt"
+ "net/http"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/config"
+ "git.curoverse.com/arvados.git/sdk/go/ctxlog"
+ "github.com/coreos/go-systemd/daemon"
+)
+
+var logger = ctxlog.FromContext
+
+func main() {
+ log := logger(nil)
+
+ configPath := flag.String("config", "/etc/arvados/ws/ws.yml", "`path` to config file")
+ dumpConfig := flag.Bool("dump-config", false, "show current configuration and exit")
+ cfg := defaultConfig()
+ flag.Parse()
+
+ err := config.LoadFile(&cfg, *configPath)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ctxlog.SetLevel(cfg.LogLevel)
+ ctxlog.SetFormat(cfg.LogFormat)
+
+ if *dumpConfig {
+ txt, err := config.Dump(&cfg)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Print(string(txt))
+ return
+ }
+
+ log.Info("started")
+ eventSource := &pgEventSource{
+ DataSource: cfg.Postgres.ConnectionString(),
+ QueueSize: cfg.ServerEventQueue,
+ }
+ srv := &http.Server{
+ Addr: cfg.Listen,
+ ReadTimeout: time.Minute,
+ WriteTimeout: time.Minute,
+ MaxHeaderBytes: 1 << 20,
+ Handler: &router{
+ Config: &cfg,
+ eventSource: eventSource,
+ newPermChecker: func() permChecker { return newPermChecker(cfg.Client) },
+ },
+ }
+ // Bootstrap the eventSource by attaching a dummy subscriber
+ // and hanging up.
+ eventSource.NewSink().Stop()
+
+ if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
+ log.WithError(err).Warn("error notifying init daemon")
+ }
+
+ log.WithField("Listen", srv.Addr).Info("listening")
+ log.Fatal(srv.ListenAndServe())
+}
--- /dev/null
+package main
+
+import (
+ "net/http"
+ "net/url"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+)
+
+const (
+ maxPermCacheAge = time.Hour
+ minPermCacheAge = 5 * time.Minute
+)
+
+type permChecker interface {
+ SetToken(token string)
+ Check(uuid string) (bool, error)
+}
+
+func newPermChecker(ac arvados.Client) permChecker {
+ ac.AuthToken = ""
+ return &cachingPermChecker{
+ Client: &ac,
+ cache: make(map[string]cacheEnt),
+ maxCurrent: 16,
+ }
+}
+
+type cacheEnt struct {
+ time.Time
+ allowed bool
+}
+
+type cachingPermChecker struct {
+ *arvados.Client
+ cache map[string]cacheEnt
+ maxCurrent int
+}
+
+func (pc *cachingPermChecker) SetToken(token string) {
+ pc.Client.AuthToken = token
+}
+
+func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
+ logger := logger(nil).
+ WithField("token", pc.Client.AuthToken).
+ WithField("uuid", uuid)
+ pc.tidy()
+ now := time.Now()
+ if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge {
+ logger.WithField("allowed", perm.allowed).Debug("cache hit")
+ return perm.allowed, nil
+ }
+ var buf map[string]interface{}
+ path, err := pc.PathForUUID("get", uuid)
+ if err != nil {
+ return false, err
+ }
+ err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
+ "select": {`["uuid"]`},
+ })
+
+ var allowed bool
+ if err == nil {
+ allowed = true
+ } else if txErr, ok := err.(*arvados.TransactionError); ok && txErr.StatusCode == http.StatusNotFound {
+ allowed = false
+ } else if txErr.StatusCode == http.StatusForbidden {
+ // Some requests are expressly forbidden for reasons
+ // other than "you aren't allowed to know whether this
+ // UUID exists" (404).
+ allowed = false
+ } else {
+ logger.WithError(err).Error("lookup error")
+ return false, err
+ }
+ logger.WithField("allowed", allowed).Debug("cache miss")
+ pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed}
+ return allowed, nil
+}
+
+func (pc *cachingPermChecker) tidy() {
+ if len(pc.cache) <= pc.maxCurrent*2 {
+ return
+ }
+ tooOld := time.Now().Add(-minPermCacheAge)
+ for uuid, t := range pc.cache {
+ if t.Before(tooOld) {
+ delete(pc.cache, uuid)
+ }
+ }
+ pc.maxCurrent = len(pc.cache)
+}
--- /dev/null
+package main
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/ctxlog"
+ "github.com/Sirupsen/logrus"
+ "golang.org/x/net/websocket"
+)
+
+type wsConn interface {
+ io.ReadWriter
+ Request() *http.Request
+ SetReadDeadline(time.Time) error
+ SetWriteDeadline(time.Time) error
+}
+
+type router struct {
+ Config *wsConfig
+ eventSource eventSource
+ newPermChecker func() permChecker
+
+ handler *handler
+ mux *http.ServeMux
+ setupOnce sync.Once
+
+ lastReqID int64
+ lastReqMtx sync.Mutex
+
+ status routerDebugStatus
+}
+
+type routerDebugStatus struct {
+ ReqsReceived int64
+ ReqsActive int64
+}
+
+type debugStatuser interface {
+ DebugStatus() interface{}
+}
+
+func (rtr *router) setup() {
+ rtr.handler = &handler{
+ PingTimeout: rtr.Config.PingTimeout.Duration(),
+ QueueSize: rtr.Config.ClientEventQueue,
+ }
+ rtr.mux = http.NewServeMux()
+ rtr.mux.Handle("/websocket", rtr.makeServer(newSessionV0))
+ rtr.mux.Handle("/arvados/v1/events.ws", rtr.makeServer(newSessionV1))
+ rtr.mux.HandleFunc("/debug.json", jsonHandler(rtr.DebugStatus))
+ rtr.mux.HandleFunc("/status.json", jsonHandler(rtr.Status))
+}
+
+func (rtr *router) makeServer(newSession sessionFactory) *websocket.Server {
+ return &websocket.Server{
+ Handshake: func(c *websocket.Config, r *http.Request) error {
+ return nil
+ },
+ Handler: websocket.Handler(func(ws *websocket.Conn) {
+ t0 := time.Now()
+ log := logger(ws.Request().Context())
+ log.Info("connected")
+
+ stats := rtr.handler.Handle(ws, rtr.eventSource,
+ func(ws wsConn, sendq chan<- interface{}) (session, error) {
+ return newSession(ws, sendq, rtr.eventSource.DB(), rtr.newPermChecker(), &rtr.Config.Client)
+ })
+
+ log.WithFields(logrus.Fields{
+ "elapsed": time.Now().Sub(t0).Seconds(),
+ "stats": stats,
+ }).Info("disconnect")
+ ws.Close()
+ }),
+ }
+}
+
+func (rtr *router) newReqID() string {
+ rtr.lastReqMtx.Lock()
+ defer rtr.lastReqMtx.Unlock()
+ id := time.Now().UnixNano()
+ if id <= rtr.lastReqID {
+ id = rtr.lastReqID + 1
+ }
+ return strconv.FormatInt(id, 36)
+}
+
+func (rtr *router) DebugStatus() interface{} {
+ s := map[string]interface{}{
+ "HTTP": rtr.status,
+ "Outgoing": rtr.handler.DebugStatus(),
+ }
+ if es, ok := rtr.eventSource.(debugStatuser); ok {
+ s["EventSource"] = es.DebugStatus()
+ }
+ return s
+}
+
+func (rtr *router) Status() interface{} {
+ return map[string]interface{}{
+ "Clients": atomic.LoadInt64(&rtr.status.ReqsActive),
+ }
+}
+
+func (rtr *router) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ rtr.setupOnce.Do(rtr.setup)
+ atomic.AddInt64(&rtr.status.ReqsReceived, 1)
+ atomic.AddInt64(&rtr.status.ReqsActive, 1)
+ defer atomic.AddInt64(&rtr.status.ReqsActive, -1)
+
+ logger := logger(req.Context()).
+ WithField("RequestID", rtr.newReqID())
+ ctx := ctxlog.Context(req.Context(), logger)
+ req = req.WithContext(ctx)
+ logger.WithFields(logrus.Fields{
+ "remoteAddr": req.RemoteAddr,
+ "reqForwardedFor": req.Header.Get("X-Forwarded-For"),
+ }).Info("accept request")
+ rtr.mux.ServeHTTP(resp, req)
+}
+
+func jsonHandler(fn func() interface{}) http.HandlerFunc {
+ return func(resp http.ResponseWriter, req *http.Request) {
+ logger := logger(req.Context())
+ resp.Header().Set("Content-Type", "application/json")
+ enc := json.NewEncoder(resp)
+ err := enc.Encode(fn())
+ if err != nil {
+ msg := "encode failed"
+ logger.WithError(err).Error(msg)
+ http.Error(resp, msg, http.StatusInternalServerError)
+ }
+ }
+}
--- /dev/null
+package main
+
+import (
+ "database/sql"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+)
+
+type session interface {
+ // Receive processes a message received from the client. If a
+ // non-nil error is returned, the connection will be
+ // terminated.
+ Receive([]byte) error
+
+ // Filter returns true if the event should be queued for
+ // sending to the client. It should return as fast as
+ // possible, and must not block.
+ Filter(*event) bool
+
+ // EventMessage encodes the given event (from the front of the
+ // queue) into a form suitable to send to the client. If a
+ // non-nil error is returned, the connection is terminated. If
+ // the returned buffer is empty, nothing is sent to the client
+ // and the event is not counted in statistics.
+ //
+ // Unlike Filter, EventMessage can block without affecting
+ // other connections. If EventMessage is slow, additional
+ // incoming events will be queued. If the event queue fills
+ // up, the connection will be dropped.
+ EventMessage(*event) ([]byte, error)
+}
+
+type sessionFactory func(wsConn, chan<- interface{}, *sql.DB, permChecker, *arvados.Client) (session, error)
--- /dev/null
+package main
+
+import (
+ "database/sql"
+ "encoding/json"
+ "errors"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "github.com/Sirupsen/logrus"
+)
+
+var (
+ errQueueFull = errors.New("client queue full")
+ errFrameTooBig = errors.New("frame too big")
+
+ sendObjectAttributes = []string{"state", "name", "owner_uuid", "portable_data_hash"}
+
+ v0subscribeOK = []byte(`{"status":200}`)
+ v0subscribeFail = []byte(`{"status":400}`)
+)
+
+type v0session struct {
+ ac *arvados.Client
+ ws wsConn
+ sendq chan<- interface{}
+ db *sql.DB
+ permChecker permChecker
+ subscriptions []v0subscribe
+ lastMsgID uint64
+ log *logrus.Entry
+ mtx sync.Mutex
+ setupOnce sync.Once
+}
+
+// newSessionV0 returns a v0 session: a partial port of the Rails/puma
+// implementation, with just enough functionality to support Workbench
+// and arv-mount.
+func newSessionV0(ws wsConn, sendq chan<- interface{}, db *sql.DB, pc permChecker, ac *arvados.Client) (session, error) {
+ sess := &v0session{
+ sendq: sendq,
+ ws: ws,
+ db: db,
+ ac: ac,
+ permChecker: pc,
+ log: logger(ws.Request().Context()),
+ }
+
+ err := ws.Request().ParseForm()
+ if err != nil {
+ sess.log.WithError(err).Error("ParseForm failed")
+ return nil, err
+ }
+ token := ws.Request().Form.Get("api_token")
+ sess.permChecker.SetToken(token)
+ sess.log.WithField("token", token).Debug("set token")
+
+ return sess, nil
+}
+
+func (sess *v0session) Receive(buf []byte) error {
+ var sub v0subscribe
+ if err := json.Unmarshal(buf, &sub); err != nil {
+ sess.log.WithError(err).Info("invalid message from client")
+ } else if sub.Method == "subscribe" {
+ sub.prepare(sess)
+ sess.log.WithField("sub", sub).Debug("sub prepared")
+ sess.sendq <- v0subscribeOK
+ sess.mtx.Lock()
+ sess.subscriptions = append(sess.subscriptions, sub)
+ sess.mtx.Unlock()
+ sub.sendOldEvents(sess)
+ return nil
+ } else {
+ sess.log.WithField("Method", sub.Method).Info("unknown method")
+ }
+ sess.sendq <- v0subscribeFail
+ return nil
+}
+
+func (sess *v0session) EventMessage(e *event) ([]byte, error) {
+ detail := e.Detail()
+ if detail == nil {
+ return nil, nil
+ }
+
+ ok, err := sess.permChecker.Check(detail.ObjectUUID)
+ if err != nil || !ok {
+ return nil, err
+ }
+
+ kind, _ := sess.ac.KindForUUID(detail.ObjectUUID)
+ msg := map[string]interface{}{
+ "msgID": atomic.AddUint64(&sess.lastMsgID, 1),
+ "id": detail.ID,
+ "uuid": detail.UUID,
+ "object_uuid": detail.ObjectUUID,
+ "object_owner_uuid": detail.ObjectOwnerUUID,
+ "object_kind": kind,
+ "event_type": detail.EventType,
+ "event_at": detail.EventAt,
+ }
+ if detail.Properties != nil && detail.Properties["text"] != nil {
+ msg["properties"] = detail.Properties
+ } else {
+ msgProps := map[string]map[string]interface{}{}
+ for _, ak := range []string{"old_attributes", "new_attributes"} {
+ eventAttrs, ok := detail.Properties[ak].(map[string]interface{})
+ if !ok {
+ continue
+ }
+ msgAttrs := map[string]interface{}{}
+ for _, k := range sendObjectAttributes {
+ if v, ok := eventAttrs[k]; ok {
+ msgAttrs[k] = v
+ }
+ }
+ msgProps[ak] = msgAttrs
+ }
+ msg["properties"] = msgProps
+ }
+ return json.Marshal(msg)
+}
+
+func (sess *v0session) Filter(e *event) bool {
+ sess.mtx.Lock()
+ defer sess.mtx.Unlock()
+ for _, sub := range sess.subscriptions {
+ if sub.match(sess, e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (sub *v0subscribe) sendOldEvents(sess *v0session) {
+ if sub.LastLogID == 0 {
+ return
+ }
+ sess.log.WithField("LastLogID", sub.LastLogID).Debug("getOldEvents")
+ // Here we do a "select id" query and queue an event for every
+ // log since the given ID, then use (*event)Detail() to
+ // retrieve the whole row and decide whether to send it. This
+ // approach is very inefficient if the subscriber asks for
+ // last_log_id==1, even if the filters end up matching very
+ // few events.
+ //
+ // To mitigate this, filter on "created > 10 minutes ago" when
+ // retrieving the list of old event IDs to consider.
+ rows, err := sess.db.Query(
+ `SELECT id FROM logs WHERE id > $1 AND created_at > $2 ORDER BY id`,
+ sub.LastLogID,
+ time.Now().UTC().Add(-10*time.Minute).Format(time.RFC3339Nano))
+ if err != nil {
+ sess.log.WithError(err).Error("db.Query failed")
+ return
+ }
+ for rows.Next() {
+ var id uint64
+ err := rows.Scan(&id)
+ if err != nil {
+ sess.log.WithError(err).Error("row Scan failed")
+ continue
+ }
+ for len(sess.sendq)*2 > cap(sess.sendq) {
+ // Ugly... but if we fill up the whole client
+ // queue with a backlog of old events, a
+ // single new event will overflow it and
+ // terminate the connection, and then the
+ // client will probably reconnect and do the
+ // same thing all over again.
+ time.Sleep(100 * time.Millisecond)
+ }
+ now := time.Now()
+ e := &event{
+ LogID: id,
+ Received: now,
+ Ready: now,
+ db: sess.db,
+ }
+ if sub.match(sess, e) {
+ select {
+ case sess.sendq <- e:
+ case <-sess.ws.Request().Context().Done():
+ return
+ }
+ }
+ }
+ if err := rows.Err(); err != nil {
+ sess.log.WithError(err).Error("db.Query failed")
+ }
+}
+
+type v0subscribe struct {
+ Method string
+ Filters []v0filter
+ LastLogID int64 `json:"last_log_id"`
+
+ funcs []func(*event) bool
+}
+
+type v0filter [3]interface{}
+
+func (sub *v0subscribe) match(sess *v0session, e *event) bool {
+ log := sess.log.WithField("LogID", e.LogID)
+ detail := e.Detail()
+ if detail == nil {
+ log.Error("match failed, no detail")
+ return false
+ }
+ log = log.WithField("funcs", len(sub.funcs))
+ for i, f := range sub.funcs {
+ if !f(e) {
+ log.WithField("func", i).Debug("match failed")
+ return false
+ }
+ }
+ log.Debug("match passed")
+ return true
+}
+
+func (sub *v0subscribe) prepare(sess *v0session) {
+ for _, f := range sub.Filters {
+ if len(f) != 3 {
+ continue
+ }
+ if col, ok := f[0].(string); ok && col == "event_type" {
+ op, ok := f[1].(string)
+ if !ok || op != "in" {
+ continue
+ }
+ arr, ok := f[2].([]interface{})
+ if !ok {
+ continue
+ }
+ var strs []string
+ for _, s := range arr {
+ if s, ok := s.(string); ok {
+ strs = append(strs, s)
+ }
+ }
+ sub.funcs = append(sub.funcs, func(e *event) bool {
+ for _, s := range strs {
+ if s == e.Detail().EventType {
+ return true
+ }
+ }
+ return false
+ })
+ } else if ok && col == "created_at" {
+ op, ok := f[1].(string)
+ if !ok {
+ continue
+ }
+ tstr, ok := f[2].(string)
+ if !ok {
+ continue
+ }
+ t, err := time.Parse(time.RFC3339Nano, tstr)
+ if err != nil {
+ sess.log.WithField("data", tstr).WithError(err).Info("time.Parse failed")
+ continue
+ }
+ var fn func(*event) bool
+ switch op {
+ case ">=":
+ fn = func(e *event) bool {
+ return !e.Detail().CreatedAt.Before(t)
+ }
+ case "<=":
+ fn = func(e *event) bool {
+ return !e.Detail().CreatedAt.After(t)
+ }
+ case ">":
+ fn = func(e *event) bool {
+ return e.Detail().CreatedAt.After(t)
+ }
+ case "<":
+ fn = func(e *event) bool {
+ return e.Detail().CreatedAt.Before(t)
+ }
+ case "=":
+ fn = func(e *event) bool {
+ return e.Detail().CreatedAt.Equal(t)
+ }
+ default:
+ sess.log.WithField("operator", op).Info("bogus operator")
+ continue
+ }
+ sub.funcs = append(sub.funcs, fn)
+ }
+ }
+}
--- /dev/null
+package main
+
+import (
+ "database/sql"
+ "errors"
+
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+)
+
+// newSessionV1 returns a v1 session -- see
+// https://dev.arvados.org/projects/arvados/wiki/Websocket_server
+func newSessionV1(ws wsConn, sendq chan<- interface{}, db *sql.DB, pc permChecker, ac *arvados.Client) (session, error) {
+ return nil, errors.New("Not implemented")
+}
--- /dev/null
+#!/bin/bash
+# bash functions for managing Arvados tokens and other conveniences.
+
+read -rd "\000" helpmessage <<EOF
+$(basename $0): bash functions for managing Arvados tokens and other shortcuts.
+
+Syntax:
+ . $0 # activate for current shell
+ $0 --install # install into .bashrc
+
+arvswitch <name>
+ Set ARVADOS_API_HOST and ARVADOS_API_TOKEN in the current environment based on
+ $HOME/.config/arvados/<name>.conf
+ With no arguments, list available Arvados configurations.
+
+arvsave <name>
+ Save values of ARVADOS_API_HOST and ARVADOS_API_TOKEN in the current environment to
+ $HOME/.config/arvados/<name>.conf
+
+arvrm <name>
+ Delete $HOME/.config/arvados/<name>.conf
+
+arvboxswitch <name>
+ Set ARVBOX_CONTAINER to <name>
+ With no arguments, list available arvboxes.
+
+arvopen:
+ Open an Arvados uuid in web browser (http://curover.se)
+
+arvissue
+ Open an Arvados ticket in web browser (http://dev.arvados.org)
+
+EOF
+
+if [[ "$1" = "--install" ]] ; then
+ this=$(readlink -f $0)
+ if ! grep ". $this" ~/.bashrc >/dev/null ; then
+ echo ". $this" >> ~/.bashrc
+ echo "Installed into ~/.bashrc"
+ else
+ echo "Already installed in ~/.bashrc"
+ fi
+elif ! [[ $0 =~ bash$ ]] ; then
+ echo "$helpmessage"
+fi
+
+HISTIGNORE=$HISTIGNORE:'export ARVADOS_API_TOKEN=*'
+
+arvswitch() {
+ if [[ -n "$1" ]] ; then
+ if [[ -f $HOME/.config/arvados/$1.conf ]] ; then
+ unset ARVADOS_API_HOST_INSECURE
+ for a in $(cat $HOME/.config/arvados/$1.conf) ; do export $a ; done
+ echo "Switched to $1"
+ else
+ echo "$1 unknown"
+ fi
+ else
+ echo "Switch Arvados environment conf"
+ echo "Usage: arvswitch name"
+ echo "Available confs:" $((cd $HOME/.config/arvados && ls --indicator-style=none *.conf) | rev | cut -c6- | rev)
+ fi
+}
+
+arvsave() {
+ if [[ -n "$1" ]] ; then
+ touch $HOME/.config/arvados/$1.conf
+ chmod 0600 $HOME/.config/arvados/$1.conf
+ env | grep ARVADOS_ > $HOME/.config/arvados/$1.conf
+ else
+ echo "Save current Arvados environment variables to conf file"
+ echo "Usage: arvsave name"
+ fi
+}
+
+arvrm() {
+ if [[ -n "$1" ]] ; then
+ if [[ -f $HOME/.config/arvados/$1.conf ]] ; then
+ rm $HOME/.config/arvados/$1.conf
+ else
+ echo "$1 unknown"
+ fi
+ else
+ echo "Delete Arvados environment conf"
+ echo "Usage: arvrm name"
+ fi
+}
+
+arvboxswitch() {
+ if [[ -n "$1" ]] ; then
+ if [[ -d $HOME/.arvbox/$1 ]] ; then
+ export ARVBOX_CONTAINER=$1
+ echo "Arvbox switched to $1"
+ else
+ echo "$1 unknown"
+ fi
+ else
+ if test -z "$ARVBOX_CONTAINER" ; then
+ ARVBOX_CONTAINER=arvbox
+ fi
+ echo "Switch Arvbox environment conf"
+ echo "Usage: arvboxswitch name"
+ echo "Your current container is: $ARVBOX_CONTAINER"
+ echo "Available confs:" $(cd $HOME/.arvbox && ls --indicator-style=none)
+ fi
+}
+
+arvopen() {
+ if [[ -n "$1" ]] ; then
+ xdg-open https://curover.se/$1
+ else
+ echo "Open Arvados uuid in browser"
+ echo "Usage: arvopen uuid"
+ fi
+}
+
+arvissue() {
+ if [[ -n "$1" ]] ; then
+ xdg-open https://dev.arvados.org/issues/$1
+ else
+ echo "Open Arvados issue in browser"
+ echo "Usage: arvissue uuid"
+ fi
+}
FROM debian:8
-RUN apt-get update
+ENV DEBIAN_FRONTEND noninteractive
-RUN DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install \
- postgresql-9.4 git build-essential runit \
- ruby rake bundler curl libpq-dev ruby-dev \
+RUN apt-get clean && \
+ apt-get update && \
+ apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
+ postgresql-9.4 git build-essential runit curl libpq-dev \
libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev \
openssh-server python-setuptools netcat-traditional \
- python-epydoc graphviz bzip2 less sudo virtualenv
-
-RUN DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install \
+ python-epydoc graphviz bzip2 less sudo virtualenv \
libpython-dev fuse libfuse-dev python-pip python-yaml \
pkg-config libattr1-dev python-llfuse python-pycurl \
libwww-perl libio-socket-ssl-perl libcrypt-ssleay-perl \
- libjson-perl nginx gitolite3 lsof \
- apt-transport-https ca-certificates slurm-wlm
+ libjson-perl nginx gitolite3 lsof libreadline-dev \
+ apt-transport-https ca-certificates slurm-wlm \
+ linkchecker python3-virtualenv python-virtualenv xvfb iceweasel && \
+ apt-get clean
-RUN apt-get update && \
- DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install \
- linkchecker python3-virtualenv python-virtualenv xvfb iceweasel
+ENV GOVERSION 1.7.3
+# Install golang binary
RUN cd /usr/local && \
- GOVERSION=1.7.1 && \
curl -O http://storage.googleapis.com/golang/go${GOVERSION}.linux-amd64.tar.gz && \
tar -xzf go${GOVERSION}.linux-amd64.tar.gz && \
- rm go${GOVERSION}.linux-amd64.tar.gz && \
- cd bin && \
- ln -s /usr/local/go/bin/* .
+ rm go${GOVERSION}.linux-amd64.tar.gz
+
+ENV PATH ${PATH}:/usr/local/go/bin
+
+ENV RUBYVERSION 2.1.8
+
+# Install Ruby from source
+RUN cd /usr/local/lib && \
+ curl -O http://cache.ruby-lang.org/pub/ruby/2.1/ruby-${RUBYVERSION}.tar.gz && \
+ tar xzf ruby-${RUBYVERSION}.tar.gz && \
+ cd ruby-${RUBYVERSION} && \
+ ./configure --disable-install-doc && \
+ make && \
+ make install && \
+ cd /usr/local/lib && \
+ rm -rf ruby-${RUBYVERSION}.tar.gz ruby-${RUBYVERSION}
+
+ENV GEM_HOME /var/lib/gems
+ENV GEM_PATH /var/lib/gems
+ENV PATH $PATH:/var/lib/gems/bin
VOLUME /var/lib/docker
VOLUME /var/log/nginx
tar -C /usr/local -xjf /tmp/$PJS.tar.bz2 && \
ln -s ../$PJS/bin/phantomjs /usr/local/bin/
+RUN pip install -U setuptools
+
ARG arvados_version
RUN echo arvados_version is git commit $arvados_version
fi
rm -rf tmp
+mkdir -p tmp/cache
bundle exec rake db:migrate
+export PATH=${PATH}:/usr/local/go/bin:/var/lib/gems/bin
+export GEM_HOME=/var/lib/gems
+export GEM_PATH=/var/lib/gems
+
if test -s /var/run/localip_override ; then
localip=$(cat /var/run/localip_override)
else
localip=$(ip addr show $defaultdev | grep 'inet ' | sed 's/ *inet \(.*\)\/.*/\1/')
fi
-export GEM_HOME=/var/lib/gems
-export GEM_PATH=/var/lib/gems
-
declare -A services
services=(
[workbench]=80
else
frozen=""
fi
+ if ! test -x bundle ; then
+ bundlergem=$(ls -r $GEM_HOME/cache/bundler-*.gem 2>/dev/null | head -n1 || true)
+ if test -n "$bundlergem" ; then
+ flock /var/lib/gems/gems.lock gem install --local --no-document $bundlergem
+ else
+ flock /var/lib/gems/gems.lock gem install --no-document bundler
+ fi
+ fi
if ! flock /var/lib/gems/gems.lock bundle install --path $GEM_HOME --local --no-deployment $frozen "$@" ; then
flock /var/lib/gems/gems.lock bundle install --path $GEM_HOME --no-deployment $frozen "$@"
fi
pip_install() {
pushd /var/lib/pip
- for p in $(ls http*.tar.gz) $(ls http*.whl) $(ls http*.zip) ; do
+ for p in $(ls http*.tar.gz) $(ls http*.tar.bz2) $(ls http*.whl) $(ls http*.zip) ; do
if test -f $p ; then
ln -sf $p $(echo $p | sed 's/.*%2F\(.*\)/\1/')
fi
/var/lib/nginx /var/log/nginx /etc/ssl/private \
/var/lib/gopath /var/lib/pip
- mkdir -p /var/lib/gems/ruby/2.1.0
- chown arvbox:arvbox -R /var/lib/gems/ruby/2.1.0
+ mkdir -p /var/lib/gems/ruby
+ chown arvbox:arvbox -R /var/lib/gems/ruby
mkdir -p /tmp/crunch0 /tmp/crunch1
chown crunch:crunch -R /tmp/crunch0 /tmp/crunch1
export RAILS_ENV=development
run_bundler --without=development
-bundle exec passenger start --runtime-check-only --runtime-dir=/var/lib/passenger
+bundle exec passenger-config build-native-support
+bundle exec passenger-config install-standalone-runtime
if test "$1" = "--only-deps" ; then
exit
fi
exec bundle exec passenger start --port=${services[api]} \
- --runtime-dir=/var/lib/passenger \
--ssl --ssl-certificate=/var/lib/arvados/self-signed.pem \
--ssl-certificate-key=/var/lib/arvados/self-signed.key
/usr/src/arvados/apps/workbench/Gemfile.lock \
/usr/src/sso/Gemfile.lock ; do
gc=$(cat $l \
- | grep -vE "(GEM|PLATFORMS|DEPENDENCIES|$^|remote:|specs:)" \
+ | grep -vE "(GEM|PLATFORMS|DEPENDENCIES|BUNDLED|GIT|$^|remote:|specs:|revision:)" \
| sed 's/^ *//' | sed 's/(.*)//' | sed 's/ *$//' | sort | uniq | wc -l)
gemlockcount=$(($gemlockcount + $gc))
done
- waiting="$waiting (installing ruby gems $gemcount/$gemlockcount)"
+ waiting="$waiting (installing ruby gems $gemcount of about $gemlockcount)"
fi
if ps x | grep -v grep | grep "c++.*/var/lib/passenger" > /dev/null ; then
fi
rm -rf tmp
+mkdir -p tmp/cache
bundle exec rake db:migrate