smartdict-gtk 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +3 -34
- data/bin/smartdict-gtk +8 -8
- data/lib/smartdict-gtk.rb +7 -1
- data/lib/smartdict/gui.rb +9 -0
- data/lib/smartdict/gui/about_window.rb +8 -6
- data/lib/smartdict/gui/cli.rb +38 -0
- data/lib/smartdict/gui/controller.rb +48 -18
- data/lib/smartdict/gui/main_window.rb +15 -1
- data/lib/smartdict/gui/text_view.rb +4 -0
- data/lib/smartdict/gui/text_view/buffer.rb +28 -0
- data/lib/smartdict/gui/version.rb +3 -0
- data/lib/smartdict/gui/word_list.rb +23 -2
- metadata +43 -10
- data/lib/smartdict.rb +0 -5
data/README.markdown
CHANGED
@@ -1,41 +1,10 @@
|
|
1
|
-
# smartdict-gtk
|
1
|
+
# smartdict-gtk [](http://travis-ci.org/smartdict/smartdict-gtk)
|
2
2
|
|
3
|
+
By [Sergey Potapov](https://github.com/greyblake)
|
3
4
|
|
4
5
|
## Installation
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#### Debian/Ubuntu
|
10
|
-
|
11
|
-
On Debian/Ubuntu you need to install the next packages:
|
12
|
-
|
13
|
-
* libglib2.0-dev
|
14
|
-
* ligatk1.0-dev
|
15
|
-
* libcairo-dev
|
16
|
-
* libsqlite3-dev
|
17
|
-
* libpango1.0-dev
|
18
|
-
|
19
|
-
To do that run:
|
20
|
-
|
21
|
-
```
|
22
|
-
apt-get install libglib2.0-dev ligatk1.0-dev libcairo-dev libsqlite3-dev libpango1.0-dev
|
23
|
-
```
|
24
|
-
|
25
|
-
Please report if you have issues or it's not complete list of required dependencies.
|
26
|
-
|
27
|
-
|
28
|
-
### Ruby version
|
29
|
-
|
30
|
-
Tested on MRI 1.9.3-p125
|
31
|
-
|
32
|
-
|
33
|
-
### Install the gem
|
34
|
-
|
35
|
-
```
|
36
|
-
gem install smartdict-gtk
|
37
|
-
```
|
38
|
-
|
7
|
+
See installation instructions for [Smartdict](https://github.com/smartdict/smartdict#installation)
|
39
8
|
|
40
9
|
|
41
10
|
## Copyright
|
data/bin/smartdict-gtk
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
# For development
|
4
|
+
parent_dir = File.expand_path('../../../', __FILE__)
|
5
|
+
Dir["#{parent_dir}/smartdict-*/lib"].each do |lib_dir|
|
6
|
+
$LOAD_PATH.unshift(lib_dir) if Dir.exists?(lib_dir)
|
7
|
+
end
|
8
|
+
|
3
9
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
4
10
|
require 'rubygems'
|
5
11
|
|
6
|
-
# For development
|
7
|
-
# require 'bundler'
|
8
|
-
# Bundler.setup(:default, :development)
|
9
|
-
|
10
12
|
require 'smartdict-core'
|
11
13
|
require 'smartdict-icons'
|
12
14
|
require 'smartdict-gtk'
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
Smartdict.run
|
17
|
-
Smartdict::Gui.run
|
16
|
+
args = ARGV.dup
|
17
|
+
Smartdict::Gui::Cli.run(args)
|
data/lib/smartdict-gtk.rb
CHANGED
data/lib/smartdict/gui.rb
CHANGED
@@ -4,7 +4,12 @@ module Smartdict::Gui
|
|
4
4
|
extend ActiveSupport::Autoload
|
5
5
|
extend self
|
6
6
|
|
7
|
+
autoload :VERSION, 'smartdict/gui/version'
|
8
|
+
|
9
|
+
autoload :Cli
|
7
10
|
autoload :Controller
|
11
|
+
|
12
|
+
# Widgets
|
8
13
|
autoload :MainWindow
|
9
14
|
autoload :WordEntry
|
10
15
|
autoload :TranslateButton
|
@@ -23,4 +28,8 @@ module Smartdict::Gui
|
|
23
28
|
def run
|
24
29
|
Smartdict::Gui::Controller.new.run
|
25
30
|
end
|
31
|
+
|
32
|
+
def root_dir
|
33
|
+
File.join(File.dirname(__FILE__), '../..')
|
34
|
+
end
|
26
35
|
end
|
@@ -10,13 +10,15 @@ class Smartdict::Gui::AboutWindow < Gtk::AboutDialog
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def set_info
|
13
|
-
|
13
|
+
info = Smartdict.info
|
14
|
+
self.name = "smartdict-gtk"
|
14
15
|
self.program_name = "Smartdict"
|
15
|
-
self.version = Smartdict::VERSION
|
16
|
-
self.copyright =
|
17
|
-
self.authors = [
|
18
|
-
self.comments = "
|
19
|
-
self.website =
|
16
|
+
self.version = Smartdict::Gui::VERSION
|
17
|
+
self.copyright = info.author
|
18
|
+
self.authors = [info.author]
|
19
|
+
self.comments = "Core v#{info.version}\nSimple dictionary"
|
20
|
+
self.website = info.url
|
21
|
+
self.logo = Gdk::Pixbuf.new(Smartdict::Icons.logo, 128, 128)
|
20
22
|
end
|
21
23
|
|
22
24
|
def set_license
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Handles options for smartdict-gtk command.
|
2
|
+
class Smartdict::Gui::Cli
|
3
|
+
def self.run(args)
|
4
|
+
case args.first
|
5
|
+
when nil, /\s+/
|
6
|
+
run_application
|
7
|
+
when '-v', '--version', 'version'
|
8
|
+
puts version_message
|
9
|
+
when '-h', '--help', 'help', /\w+/
|
10
|
+
puts help_message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.run_application
|
18
|
+
Smartdict.env = :user
|
19
|
+
Smartdict.run
|
20
|
+
Smartdict::Gui.run
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.version_message
|
24
|
+
info = Smartdict.info
|
25
|
+
"Smartdict GUI(gtk) v#{Smartdict::Gui::VERSION}\n" \
|
26
|
+
"Smartdict core v#{info.version}\n" \
|
27
|
+
"Author: #{info.author} (#{info.email})\n" \
|
28
|
+
"URL: #{info.url}\n" \
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.help_message
|
32
|
+
"Smartdict GUI(gtk)\n\n" \
|
33
|
+
" Usage:\n" \
|
34
|
+
" smartdict-gtk run the application\n" \
|
35
|
+
" smartdict-gtk --version see version\n" \
|
36
|
+
" smartdict-gtk --help see help message\n" \
|
37
|
+
end
|
38
|
+
end
|
@@ -1,27 +1,36 @@
|
|
1
|
-
require 'benchmark'
|
2
|
-
|
3
1
|
module Smartdict::Gui
|
4
2
|
class Controller
|
5
3
|
extend ActiveSupport::Autoload
|
6
4
|
autoload :Config
|
7
5
|
|
6
|
+
HISTORY_SIZE_ON_START = 50
|
7
|
+
|
8
8
|
attr_reader :main_window, :word_entry, :translate_button, :menu_bar, :text_view, :status_icon,
|
9
9
|
:from_lang_combo_box, :to_lang_combo_box, :interchange_button, :word_list
|
10
10
|
|
11
11
|
def initialize
|
12
|
+
@translator = Smartdict::Translator.new(
|
13
|
+
:from_lang => config.from_lang,
|
14
|
+
:to_lang => config.to_lang,
|
15
|
+
:log => true
|
16
|
+
)
|
17
|
+
|
12
18
|
@main_window = MainWindow.new(self)
|
13
19
|
@word_entry = WordEntry.new(self)
|
14
20
|
@translate_button = TranslateButton.new(self)
|
15
21
|
@menu_bar = MenuBar.new(self)
|
16
22
|
@text_view = TextView.new(self)
|
17
23
|
@status_icon = StatusIcon.new(self)
|
18
|
-
@from_lang_combo_box = LangComboBox.new(self, config.from_lang)
|
19
|
-
|
24
|
+
@from_lang_combo_box = LangComboBox.new(self, config.from_lang) do |lang|
|
25
|
+
@translator.default_opts[:from_lang] = lang
|
26
|
+
end
|
27
|
+
@to_lang_combo_box = LangComboBox.new(self, config.to_lang) do |lang|
|
28
|
+
@translator.default_opts[:to_lang] = lang
|
29
|
+
end
|
20
30
|
@interchange_button = InterchangeButton.new(self)
|
21
31
|
@word_list = WordList.new(self)
|
22
32
|
|
23
|
-
|
24
|
-
#exit
|
33
|
+
load_history
|
25
34
|
end
|
26
35
|
|
27
36
|
def run
|
@@ -36,28 +45,33 @@ module Smartdict::Gui
|
|
36
45
|
|
37
46
|
def translate
|
38
47
|
word = @word_entry.text.strip.downcase
|
39
|
-
|
48
|
+
from_lang = @translator.default_opts[:from_lang]
|
49
|
+
to_lang = @translator.default_opts[:to_lang]
|
50
|
+
|
51
|
+
if add_to_history?(word, from_lang, to_lang)
|
52
|
+
translation = @translator.translate(word)
|
53
|
+
add_to_history(translation)
|
54
|
+
else
|
55
|
+
translation = @translator.translate(word, :log => false)
|
56
|
+
end
|
40
57
|
@text_view.show_translation(translation)
|
41
|
-
@word_list.
|
42
|
-
rescue Smartdict::TranslationNotFound =>
|
43
|
-
@text_view.buffer.text =
|
58
|
+
@word_list.scroll_up
|
59
|
+
rescue Smartdict::TranslationNotFound => error
|
60
|
+
@text_view.buffer.text = error.message
|
61
|
+
rescue Exception => error
|
62
|
+
@text_view.show_error(error)
|
44
63
|
end
|
45
64
|
|
46
65
|
# @param [String] word
|
47
66
|
# @param [String] from_lang language code
|
48
67
|
# @param [String] to_lang language code
|
49
68
|
def translate_selected_word(word, from_lang, to_lang)
|
50
|
-
translation =
|
69
|
+
translation = @translator.translate(word, :log => false)
|
51
70
|
@text_view.show_translation(translation)
|
52
71
|
end
|
53
72
|
|
54
73
|
def toggle_main_window
|
55
|
-
|
56
|
-
@main_window.hide_all
|
57
|
-
else
|
58
|
-
@main_window.show_all
|
59
|
-
@main_window.present
|
60
|
-
end
|
74
|
+
@main_window.toggle_visibility
|
61
75
|
end
|
62
76
|
|
63
77
|
def open_about_window
|
@@ -70,7 +84,7 @@ module Smartdict::Gui
|
|
70
84
|
|
71
85
|
def export_translations(format_name, file_path, options = {})
|
72
86
|
format = Smartdict::Core::FormatManager.find(format_name)
|
73
|
-
translations = Smartdict::
|
87
|
+
translations = Smartdict::Log.fetch(options)
|
74
88
|
content = format.format_list(translations)
|
75
89
|
File.open(file_path, 'w') { |file| file.write content }
|
76
90
|
end
|
@@ -85,5 +99,21 @@ module Smartdict::Gui
|
|
85
99
|
def config
|
86
100
|
@config ||= Config.new
|
87
101
|
end
|
102
|
+
|
103
|
+
def add_to_history?(word, from_lang, to_lang)
|
104
|
+
!@word_list.first_item_matches?(word, from_lang, to_lang)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_to_history(translation)
|
108
|
+
@word_list.prepend_word(translation)
|
109
|
+
end
|
110
|
+
|
111
|
+
def load_history
|
112
|
+
translations = Smartdict::Log.fetch(:order_desc => true, :limit => HISTORY_SIZE_ON_START)
|
113
|
+
translations.reverse.each do |tr|
|
114
|
+
@word_list.prepend_word(tr)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
88
118
|
end
|
89
119
|
end
|
@@ -10,7 +10,7 @@ class Smartdict::Gui::MainWindow < ::Gtk::Window
|
|
10
10
|
|
11
11
|
@controller = controller
|
12
12
|
|
13
|
-
signal_connect("delete_event") {
|
13
|
+
signal_connect("delete_event") { @controller.toggle_main_window }
|
14
14
|
signal_connect("destroy") { @controller.quit }
|
15
15
|
|
16
16
|
set_default_size(720, 450)
|
@@ -61,4 +61,18 @@ class Smartdict::Gui::MainWindow < ::Gtk::Window
|
|
61
61
|
add(main_box)
|
62
62
|
end
|
63
63
|
|
64
|
+
|
65
|
+
def toggle_visibility
|
66
|
+
if self.visible? and self.active?
|
67
|
+
@prev_position = self.position
|
68
|
+
self.hide_all
|
69
|
+
elsif self.visible? and !self.active?
|
70
|
+
self.present
|
71
|
+
else
|
72
|
+
self.show_all
|
73
|
+
self.move(*@prev_position)
|
74
|
+
self.present
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
64
78
|
end
|
@@ -7,6 +7,7 @@ class Smartdict::Gui::TextView::Buffer < ::Gtk::TextBuffer
|
|
7
7
|
create_tag("transcription" , {"style" => Pango::STYLE_ITALIC, :scale => 1.3})
|
8
8
|
create_tag("word_class" , {"weight" => Pango::WEIGHT_BOLD , :scale => 1.0})
|
9
9
|
create_tag("translated_word", {:scale => 1.0})
|
10
|
+
create_tag("text", {})
|
10
11
|
end
|
11
12
|
|
12
13
|
def set_translation(translation)
|
@@ -21,6 +22,16 @@ class Smartdict::Gui::TextView::Buffer < ::Gtk::TextBuffer
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
25
|
+
def set_error(error)
|
26
|
+
self.text = ''
|
27
|
+
insert_text "An error occured. Please report it: \n"
|
28
|
+
insert_url "https://github.com/smartdict/smartdict-gtk/issues/new"
|
29
|
+
insert_text "\n\nError information:\n" \
|
30
|
+
" #{error.class}: #{error.message}\n\n" \
|
31
|
+
"Backtrace:\n"
|
32
|
+
insert_text " " + error.backtrace.join("\n ")
|
33
|
+
end
|
34
|
+
|
24
35
|
|
25
36
|
private
|
26
37
|
|
@@ -36,4 +47,21 @@ class Smartdict::Gui::TextView::Buffer < ::Gtk::TextBuffer
|
|
36
47
|
word_text = (" " * INDENT * 2) + "#{word}\n"
|
37
48
|
insert(end_iter, word_text, "translated_word")
|
38
49
|
end
|
50
|
+
|
51
|
+
# TODO: implement
|
52
|
+
# There is no legal way to display link with Ruby.
|
53
|
+
# See Python solution for _insert_url(): http://download.gna.org/nfoview/doc/api/nfoview.view_source.html
|
54
|
+
def insert_url(url)
|
55
|
+
tag = create_tag(nil, {"underline" => Pango::UNDERLINE_SINGLE, "foreground" => "blue"})
|
56
|
+
#tag.signal_connect("event") do |tag, text_view, event, itr|
|
57
|
+
# if event.event_type == Gdk::Event::BUTTON_RELEASE
|
58
|
+
# puts url
|
59
|
+
# end
|
60
|
+
#end
|
61
|
+
insert(end_iter, url, tag)
|
62
|
+
end
|
63
|
+
|
64
|
+
def insert_text(text)
|
65
|
+
insert(end_iter, text, "text")
|
66
|
+
end
|
39
67
|
end
|
@@ -15,8 +15,7 @@ class Smartdict::Gui::WordList < ::Gtk::TreeView
|
|
15
15
|
# set options of column
|
16
16
|
self.resizable = true
|
17
17
|
self.clickable = true
|
18
|
-
self.
|
19
|
-
self.sort_column_id = column_id
|
18
|
+
self.reorderable = false
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -42,6 +41,28 @@ class Smartdict::Gui::WordList < ::Gtk::TreeView
|
|
42
41
|
item[0] = translation.word
|
43
42
|
item[1] = translation.from_lang
|
44
43
|
item[2] = translation.to_lang
|
44
|
+
selection.select_iter(item)
|
45
|
+
end
|
46
|
+
|
47
|
+
def first_item_matches?(word, from_lang, to_lang)
|
48
|
+
iter = @list_model.iter_first
|
49
|
+
return false unless iter
|
50
|
+
word == @list_model.get_value(iter, 0) &&
|
51
|
+
from_lang == @list_model.get_value(iter, 1) &&
|
52
|
+
to_lang == @list_model.get_value(iter, 2)
|
53
|
+
end
|
54
|
+
|
55
|
+
def scroll_up
|
56
|
+
# TODO: It's a dirty hack!
|
57
|
+
# We need just resize WordList and set vadjustment.value = 0.
|
58
|
+
# But WordList is resized after, so I do this hack to make sure
|
59
|
+
# that it's already resized.
|
60
|
+
Thread.new do
|
61
|
+
# Expected to parent be Gtk::ScrolledWindow
|
62
|
+
vad = self.parent.vadjustment
|
63
|
+
vad.value = vad.lower
|
64
|
+
vad.value_changed
|
65
|
+
end
|
45
66
|
end
|
46
67
|
|
47
68
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartdict-gtk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: smartdict-core
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 0.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 0.1.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: smartdict-icons
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 1.1.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: activesupport
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.2.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.2.0
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
79
|
name: dm-enum
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,7 +114,7 @@ dependencies:
|
|
98
114
|
requirements:
|
99
115
|
- - ~>
|
100
116
|
- !ruby/object:Gem::Version
|
101
|
-
version: 2.
|
117
|
+
version: '2.7'
|
102
118
|
type: :development
|
103
119
|
prerelease: false
|
104
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +122,7 @@ dependencies:
|
|
106
122
|
requirements:
|
107
123
|
- - ~>
|
108
124
|
- !ruby/object:Gem::Version
|
109
|
-
version: 2.
|
125
|
+
version: '2.7'
|
110
126
|
- !ruby/object:Gem::Dependency
|
111
127
|
name: bundler
|
112
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +155,22 @@ dependencies:
|
|
139
155
|
- - ~>
|
140
156
|
- !ruby/object:Gem::Version
|
141
157
|
version: 1.6.4
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: aruba
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - '='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.4.11
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - '='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.4.11
|
142
174
|
description: GTK GUI for Smartdict dictionary
|
143
175
|
email: blake131313@gmail.com
|
144
176
|
executables:
|
@@ -149,9 +181,9 @@ extra_rdoc_files:
|
|
149
181
|
files:
|
150
182
|
- ./bin/smartdict-gtk
|
151
183
|
- ./lib/smartdict-gtk.rb
|
152
|
-
- ./lib/smartdict.rb
|
153
184
|
- ./lib/smartdict/gui.rb
|
154
185
|
- ./lib/smartdict/gui/about_window.rb
|
186
|
+
- ./lib/smartdict/gui/cli.rb
|
155
187
|
- ./lib/smartdict/gui/controller.rb
|
156
188
|
- ./lib/smartdict/gui/controller/config.rb
|
157
189
|
- ./lib/smartdict/gui/export_dialog.rb
|
@@ -164,6 +196,7 @@ files:
|
|
164
196
|
- ./lib/smartdict/gui/text_view.rb
|
165
197
|
- ./lib/smartdict/gui/text_view/buffer.rb
|
166
198
|
- ./lib/smartdict/gui/translate_button.rb
|
199
|
+
- ./lib/smartdict/gui/version.rb
|
167
200
|
- ./lib/smartdict/gui/word_entry.rb
|
168
201
|
- ./lib/smartdict/gui/word_list.rb
|
169
202
|
- GPL-LICENSE.txt
|
@@ -191,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
224
|
version: '0'
|
192
225
|
requirements: []
|
193
226
|
rubyforge_project:
|
194
|
-
rubygems_version: 1.8.
|
227
|
+
rubygems_version: 1.8.24
|
195
228
|
signing_key:
|
196
229
|
specification_version: 3
|
197
230
|
summary: GTK GUI for Smartdict dictionary
|