dyndoc-ruby 1.2.0 → 1.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e42fea0e78789262abc853bd7b2b328216b2a5f025a7dfcd161c367d57ceb23d
4
- data.tar.gz: b30acf3518b75e7449c85f6a886e7f7b02ddc1fb61054726ba329ee524f3a70b
3
+ metadata.gz: de8974d835f1c28fe519e9dcad144c6df472418b1722e64c1170024a297463fb
4
+ data.tar.gz: 729c42dcf5a03ba6b23230547b48be9a184861fabb0b16445aafde9a2677e7ec
5
5
  SHA512:
6
- metadata.gz: 7b0c2d715135a5f40309b679b2dd4e40cbfeb51b38672afeb1015b805693a77085f52ddd1a4ff0ab5511f970fbb161fcc0f74485fb8522dc07d62bfe324712ec
7
- data.tar.gz: 1d2b63f650ac19af353cf70f1637e76c96b232234c2f9ccaaaf5f872f53b1eaf9b4066e665f0f80d33f4ed07b38582071a4b6692f4d0a34088f6196ebad123ae
6
+ metadata.gz: 89fa832cd2e117b83373e5b2b40c18cd106034a7235cceceaa3f6c33ac417419814338ca7e8a66b94bfacda69b696a2fd4621cce847008559bd7cdb4614c57a5
7
+ data.tar.gz: 1ee53e1c3a5e452c2131591309c6cf2260f2474d8a679ee174b91c2dc957f30bc1c9433972f9ff7ed68e7d98fe6006af4acd1638adc1b7edb0d5aab33ca5e493
data/bin/dyn CHANGED
@@ -78,6 +78,10 @@ OptionParser.new do |opts|
78
78
  Settings['cfg_dyn.debug']=true
79
79
  end
80
80
 
81
+ opts.on('-r','--rb_only','ruby only mode') do
82
+ Settings['cfg_dyn.ruby_only']=true
83
+ end
84
+
81
85
  opts.on("-p", "--pandoc ", "filter for pandoc (tex2docx,...)") do |f|
82
86
  #p [:pandoc,f]
83
87
  Settings["cfg_dyn.pandoc_filter"] = f
@@ -57,7 +57,6 @@ when "unwatch"
57
57
  Dyndoc::HtmlServers.unwatch_rm path
58
58
  end
59
59
 
60
-
61
60
  when "start"
62
61
  status=SRVS.map do |srv|
63
62
  `#{srv} status`.empty?
@@ -89,7 +88,7 @@ when "new"
89
88
  FileUtils.mkdir_p File.join(ENV["HOME"],"dyndoc",'log')
90
89
 
91
90
  unless File.exists? DYNCTL_PLIST
92
- plist= <<-END.sub(/CMD/,CMD).sub(/DYN_CMD/,`which #{CMD}`.strip).sub(/ERR_FILE/,DYNCTL_ERR_FILE).sub(/OUT_FILE/,DYNCTL_OUT_FILE).sub(/DYN_PATH/,ENV["PATH"]).sub(/DYN_LANG/,ENV["LANG"]).sub(/DYN_JULIA_DIR/,ENV["JULIA_DIR"] || "")
91
+ plist= <<-END.sub(/CMD/,CMD).sub(/DYN_CMD/,`which #{CMD}`.strip).sub(/ERR_FILE/,DYNCTL_ERR_FILE).sub(/OUT_FILE/,DYNCTL_OUT_FILE).sub(/DYN_PATH/,ENV["PATH"]).sub(/DYN_LANG/,ENV["LANG"]).sub(/DYN_JULIA_DIR/,ENV["JULIA_DIR"] || "").sub(/DYN_JULIA_RUBYLIB_PATH/,ENV["JULIA_RUBYLIB_PATH"])
93
92
  <?xml version="1.0" encoding="UTF-8"?>
94
93
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
95
94
  <plist version="1.0">
@@ -102,6 +101,10 @@ when "new"
102
101
  <string>DYN_LANG</string>
103
102
  <key>JULIA_DIR</key>
104
103
  <string>DYN_JULIA_DIR</string>
104
+ <key>JULIA_RUBYLIB_PATH</key>
105
+ <string>DYN_JULIA_RUBYLIB_PATH</string>
106
+ <key>OBJC_DISABLE_INITIALIZE_FORK_SAFETY</key>
107
+ <string>YES</string>
105
108
  </dict>
106
109
  <key>Label</key>
107
110
  <string>CMD</string>
@@ -15,6 +15,13 @@ args=ARGV.select{|name|
15
15
 
16
16
  args=["-h"] if args.empty?
17
17
 
18
+ # Default for dyn-yml is without :R and :jl and :exec_mode activated since it is tailor-made for managing task
19
+ # use option -R to activate :R (and :jl if declared in ~/.dyndoc.yml)
20
+ Settings['cfg_dyn.ruby_only']=true
21
+ # use option -w (like write) to deactivate exec_mode
22
+ Settings["cfg_dyn.model_doc"] = "Content"
23
+ Settings["cfg_dyn.exec_mode"] = "yes"
24
+
18
25
  require 'optparse'
19
26
 
20
27
  OptionParser.new do |opts|
@@ -34,9 +41,9 @@ OptionParser.new do |opts|
34
41
  Settings["cfg_dyn.model_doc"] = "Content"
35
42
  end
36
43
 
37
- opts.on('-x',"--exec_only", "exec only mode (no document!)") do
38
- Settings["cfg_dyn.model_doc"] = "Content"
39
- Settings["cfg_dyn.exec_mode"] = "yes"
44
+ opts.on('-w',"--no_exec_only", "exec only mode (no document!)") do
45
+ Settings["cfg_dyn.model_doc"] = "default"
46
+ Settings["cfg_dyn.exec_mode"] = "no"
40
47
  end
41
48
 
42
49
  opts.on('-c', '--cmd COMMAND','[a(rchive old)][r(emove old)][s(ave)][pdf(latex)]') {|c|
@@ -72,6 +79,10 @@ OptionParser.new do |opts|
72
79
  Settings['cfg_dyn.debug']=true
73
80
  end
74
81
 
82
+ opts.on('-R','--no_rb_only','no ruby only mode') do
83
+ Settings['cfg_dyn.ruby_only']=false
84
+ end
85
+
75
86
  opts.on("-p", "--pandoc ", "filter for pandoc (tex2docx,...)") do |f|
76
87
  #p [:pandoc,f]
77
88
  Settings["cfg_dyn.pandoc_filter"] = f
@@ -92,14 +103,52 @@ require 'fileutils'
92
103
 
93
104
  cfg_yml=YAML::load_file(doc)
94
105
 
95
- doc =~ /^(.*)_dyn.yml$/
106
+ doc =~ /^(.*)_dyn\.yml$/
96
107
  docname=$1
97
108
 
98
- if dyntaskname=cfg_yml["dyntask"]
99
- puts dyntaskname
100
- if File.exists? dyntaskname
109
+ unless cfg_yml["dyntask"]
110
+ #attempt to know if format is the simplified one for workflow
111
+ ks=cfg_yml.keys
112
+ cfg2={"dyntask" => "workflow", "params" => {"id" => ks[0], "workdir" => cfg_yml[ks[0]]}}
113
+ tasks={}
114
+ ks[1..-1].each do |t|
115
+ kt,*pt=cfg_yml[t].strip.split("\n")
116
+ wt,tn=kt.strip.split("->").map{|e| e.strip if e}
117
+ if tn
118
+ tasks[t]={"dyntask" => tn}
119
+ wt="init" if wt.empty?
120
+ tasks[t]["wait"]=wt
121
+ pt=YAML::load(pt.join("\n"))
122
+ tasks[t]["params"]=pt
123
+ else
124
+ puts "Warning: task "+ t + " not considered because malformed"
125
+ end
126
+ end
127
+ cfg2["params"]["tasks"]=tasks
128
+ cfg_yml=cfg2
129
+ end
130
+
131
+ dyntaskname=cfg_yml["dyntask"]
132
+
133
+ if dyntaskname
134
+ puts dyntaskname
135
+ dyntaskname += "_task.dyn" unless dyntaskname=~/_task.dyn$/
136
+ dyntaskpath=dyntaskname
137
+ is_dyntask=File.exists? dyntaskpath
138
+ unless is_dyntask
139
+ dyntaskpath=File.join(ENV["HOME"],"dyndoc","tasks",dyntaskname)
140
+ is_dyntask=File.exists? dyntaskpath
141
+ end
142
+ unless is_dyntask
143
+ share_path=File.expand_path("../../share", __FILE__)
144
+ dyntaskpath=File.join(share_path,"dyntasks",dyntaskname)
145
+ is_dyntask=File.exists? dyntaskpath
146
+ end
147
+ if is_dyntask
101
148
  dynfile=docname+".dyn"
102
- FileUtils.cp dyntaskname, dynfile
149
+ FileUtils.cp dyntaskpath, dynfile
150
+ $params=cfg_yml["params"]
151
+ $dyntask=dyntaskname
103
152
  cfg_yml["params"].each do |key,val|
104
153
  Settings["cfg_dyn.user_input"] << [key,val]
105
154
  end
@@ -0,0 +1 @@
1
+ [#rb<]$params["files"].each {|f| system("rm "+f)}
@@ -0,0 +1 @@
1
+ [#rb<]system("pdflatex "+$params['input'])
@@ -0,0 +1,82 @@
1
+ [#%]Création de tâches à lancer en mode asynchone (mode synchrone comme un cas particulier)
2
+
3
+ L'idée est :
4
+ * de créer des fichiers _dyn.yml qui seront en charge de définir les tâches à exécuter en asynchrone
5
+ * de créer en même temps le script bash pour effectivement lancer ces tâches
6
+ * puis en fin de lancer le script de tâche qui sera exécuté dans un répertoire de travail associé au projet
7
+
8
+ [#?]!(wd=$params["workdir"]).empty? [#%]Rien à faire si pas de workdir
9
+ [#=]prj_id[:{$params["id"]}]
10
+ [#<]
11
+
12
+ {#def]waitfor[#,]task[][#,]cond[] [#,]cpt_max[20] [#,]lag[.5]
13
+ [#rb<]
14
+ prj=$params["id"]
15
+ wait_cond=#{=cond}.split("&").map{|e| " [ ! -e " + prj + "-" + e.strip + ".task ]" }.join(" && ")
16
+ [#>][
17
+ waitfor_:{prj}_#{task}() {
18
+ local cpt="0"
19
+ echo "waiting for task #{task} in project :{prj}"
20
+ while :{wait_cond} && [ $cpt != "#{cpt_max}" ]
21
+ do
22
+ sleep #{lag}
23
+ # echo -ne "."
24
+ cpt=$(($cpt+1))
25
+ done
26
+ #echo ""
27
+ if [ $cpt -eq "#{cpt_max}" ]
28
+ then
29
+ return 1
30
+ else
31
+ return 0
32
+ fi
33
+ }
34
+ ]
35
+ [#def}
36
+
37
+ [#rb<]
38
+ require 'yaml'
39
+ cfg_yml = File.join(Dyndoc.home,"etc","dyn-html.yml")
40
+ dynworld_root=cfg_yml["dynworld_root"] || File.join(ENV["HOME"],".dyndoc-world")
41
+ wd=File.join(dynworld_root,wd)
42
+
43
+ FileUtils.rm_rf wd if Dir.exist? wd
44
+ FileUtils.mkdir_p wd
45
+ shscript=""
46
+ prj_id=#{=prj_id}
47
+ # Creation of dyn tasks (_dyn.yml files)
48
+ tasks=$params["tasks"]
49
+ #p [:tasks,tasks.keys]
50
+ ## shell fcts
51
+ tasks.keys.each do |task| #
52
+ ## puts "task: "+task+"\n"
53
+ task_id = (task[-1,1]==">" ? task[0..-2] : task)
54
+ task_cond=tasks[task]["wait"]
55
+ {#<][#rb<]
56
+ |shscript << %Q(
57
+ |{#waitfor]:{task_id}[#cond]:{task_cond}[#}
58
+ |)
59
+ [#<}
60
+ end
61
+ ## shell script
62
+ shscript << "cd " + wd + "\n"
63
+ tasks.keys.each do |task| #
64
+ ## puts "task: "+task+"\n"
65
+ task_id = (task[-1,1]==">" ? task[0..-2] : task)
66
+ task_yml = File.join(wd,prj_id+"-"+task_id+"_dyn.yml")
67
+ puts "Creating "+task_yml+"\n"
68
+ begin
69
+ dyntask=(tasks[task].is_a? String) ? tasks[tasks[task]] : tasks[task]
70
+ dyntask=dyntask.select{|k| ["dyntask","params"].include? k}
71
+ #p [:dyntask,dyntask,dyntask.empty?]
72
+ File.open(task_yml,"w") {|f| f << dyntask.to_yaml } unless dyntask.empty?
73
+ rescue
74
+ puts "Task not created\n"
75
+ end
76
+ shscript << "{ waitfor_" << prj_id << "_" << task_id << " && dyn-yml " << ( task_id[0,1] == task_id[0,1].upcase ? "-R " : "") << ( task_id == task ? "" : "-w ") << prj_id << "-" << task_id << "_dyn.yml " << "&& touch " << prj_id << "-" << task_id << ".task; } &\n"
77
+ end
78
+ shscript << "touch "+ prj_id + "-init.task\n"
79
+ #p [:script,shscript]
80
+ File.open(File.join(wd,"task.sh"),"w") {|f| f << shscript}
81
+ Process.spawn(". " +File.join(wd,"task.sh"))
82
+ [#?]end
@@ -10,6 +10,12 @@ cfg.merge! YAML::load_file(cfg_yml) if File.exist? cfg_yml
10
10
  root = cfg["root"] || File.join(ENV["HOME"],"RCqls","RodaServer")
11
11
  $public_root = cfg["public_root"] || File.join(root ,"public")
12
12
  ##p [:public_root,$public_root]
13
+ $dynworld_root=cfg["dynworld_root"] || File.join(ENV["HOME"],".dyndoc-world")
14
+ $dynworld_tools=cfg["dynworld_tools"] || File.join(ENV["HOME"],"Gogs","dynworld")
15
+ if Dir.exists? $dynworld_tools
16
+ require File.join($dynworld_tools,"tools.rb")
17
+ puts "Dynworld activated"
18
+ end
13
19
 
14
20
  class App < Roda
15
21
  use Rack::Session::Cookie, :secret => (secret="Thanks like!")
@@ -35,16 +41,54 @@ class App < Roda
35
41
  r.redirect "/hello"
36
42
  end
37
43
 
38
- r.post "dyndoc-yml" do
39
- puts "dyndoc-yml"
40
- @yml,@content=r['yml'],r['content']
41
- p [@yml,@content]
42
- require 'fileutils'
43
- if @yml
44
- dynappsdir=File.join(ENV["HOME"],".dyndoc-apps")
45
- File.open(File.join(dynappsdir,@yml),"w") {|f| f << @content.strip} if Dir.exists? dynappsdir
44
+ r.on "dynworld" do
45
+
46
+ r.post "file-save" do
47
+ puts "file-save"
48
+ prj,yml,@file,@content=r['prj'].strip,r['yml'].strip,r['file'].strip,r['content']
49
+ p [prj,yml,@file,@content]
50
+ success=false
51
+ unless yml.empty?
52
+ yml="---\n" + yml unless yml[0,4] == "---\n"
53
+ yml=YAML::load(yml)
54
+ p [:yml, yml]
55
+ require 'fileutils'
56
+ if @file and !(@file.include? "../") and (DyndocWorld.yml?(prj,yml))
57
+ if Dir.exists? $dynworld_root
58
+ prj_dir=DyndocWorld.prj_dir(prj,yml)
59
+ dynworld_file=File.join($dynworld_root,prj_dir,@file)
60
+ FileUtils.mkdir_p File.dirname dynworld_file
61
+ File.open(dynworld_file,"w") {|f| f << @content.strip}
62
+ success=true
63
+ end
64
+ end
65
+ end
66
+ "{success: " + success.to_s + "}"
46
67
  end
47
- r.redirect "/hello"
68
+
69
+ r.post "file-upload" do
70
+ uploaded_io = r[:file]
71
+ ##
72
+ p [:uploaded_io, uploaded_io]
73
+ @upload_dir=r["upload_dir"]
74
+ p [:file_upload_dir,@upload_dir]
75
+ # FileUtils.mkdir_p File.join(@upload_dir_root,@upload_dir)
76
+ # uploaded_io[:filename].gsub("'","_") if uploaded_io[:filename].include? "'"
77
+ # File.open(File.join(@upload_dir_root,@upload_dir, uploaded_io[:filename]), 'wb') do |file|
78
+ # file.write(uploaded_io[:tempfile].read)
79
+ # end
80
+ "{success: true}"
81
+ end
82
+
83
+ r.post "file-delete" do
84
+ @upload_dir=r["upload_dir"]
85
+ p @upload_dir
86
+ # deleted_file=File.join(@upload_dir_root,@upload_dir,r[:file_name])
87
+ # ##p deleted_file
88
+ # FileUtils.rm(deleted_file)
89
+ "{success: true}"
90
+ end
91
+
48
92
  end
49
93
 
50
94
  #r.multi_route
@@ -91,33 +135,6 @@ class App < Roda
91
135
  end
92
136
  =end
93
137
 
94
- r.on "dropzone" do
95
-
96
- r.post "file-upload" do
97
- uploaded_io = r[:file]
98
- ##
99
- p [:uploaded_io, uploaded_io]
100
- @upload_dir=r["upload_dir"]
101
- p [:file_upload_dir,@upload_dir]
102
- # FileUtils.mkdir_p File.join(@upload_dir_root,@upload_dir)
103
- # uploaded_io[:filename].gsub("'","_") if uploaded_io[:filename].include? "'"
104
- # File.open(File.join(@upload_dir_root,@upload_dir, uploaded_io[:filename]), 'wb') do |file|
105
- # file.write(uploaded_io[:tempfile].read)
106
- # end
107
- "{success: true}"
108
- end
109
-
110
- r.post "file-delete" do
111
- @upload_dir=r["upload_dir"]
112
- p @upload_dir
113
- # deleted_file=File.join(@upload_dir_root,@upload_dir,r[:file_name])
114
- # ##p deleted_file
115
- # FileUtils.rm(deleted_file)
116
- "{success: true}"
117
- end
118
-
119
- end
120
-
121
138
  r.get do
122
139
  check_csrf!
123
140
  page=r.remaining_path
@@ -132,13 +149,13 @@ class App < Roda
132
149
  end
133
150
 
134
151
  ## Added to protect page
135
- protect = nil
152
+ @protect = "no"
136
153
  if (page[0...8] == "/protect")
137
154
  page=page[8..-1]
138
155
  if page =~ /^\/([^\/]*)\/(.*)$/
139
- protect, page = $1, '/' + $2
156
+ @protect, page = $1, '/' + $2
140
157
  end
141
- p [:protect, protect, page]
158
+ p [:protect, @protect, page]
142
159
  end
143
160
 
144
161
  ##p [:page,File.join(static_root,"**",page+".html")]
metadata CHANGED
@@ -1,95 +1,95 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dyndoc-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - RCqls
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-16 00:00:00.000000000 Z
11
+ date: 2019-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: R4rb
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
19
  version: 1.0.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '1.0'
30
27
  - - ">="
31
28
  - !ruby/object:Gem::Version
32
29
  version: 1.0.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: dyndoc-ruby-core
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '1.0'
40
37
  - - ">="
41
38
  - !ruby/object:Gem::Version
42
39
  version: 1.0.0
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '1.0'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '1.0'
50
47
  - - ">="
51
48
  - !ruby/object:Gem::Version
52
49
  version: 1.0.0
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '1.0'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: dyndoc-ruby-doc
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: '1.0'
60
57
  - - ">="
61
58
  - !ruby/object:Gem::Version
62
59
  version: 1.0.0
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: '1.0'
70
67
  - - ">="
71
68
  - !ruby/object:Gem::Version
72
69
  version: 1.0.0
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '1.0'
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: dyndoc-ruby-exec
75
75
  requirement: !ruby/object:Gem::Requirement
76
76
  requirements:
77
- - - "~>"
78
- - !ruby/object:Gem::Version
79
- version: '0.1'
80
77
  - - ">="
81
78
  - !ruby/object:Gem::Version
82
79
  version: 0.1.0
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
83
  type: :runtime
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '0.1'
90
87
  - - ">="
91
88
  - !ruby/object:Gem::Version
92
89
  version: 0.1.0
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '0.1'
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: asciidoctor
95
95
  requirement: !ruby/object:Gem::Requirement
@@ -224,6 +224,9 @@ files:
224
224
  - share/demo/test_atom.dyn
225
225
  - share/dyndoc.yml/README.md
226
226
  - share/dyndoc.yml/example.dyndoc.yml
227
+ - share/dyntasks/clean_task.dyn
228
+ - share/dyntasks/pdflatex_task.dyn
229
+ - share/dyntasks/workflow_task.dyn
227
230
  - share/etc/alias
228
231
  - share/etc/dyn-cli/dyn_layout
229
232
  - share/etc/dyn-cli/layout/default.dyn
@@ -498,8 +501,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
498
501
  version: '0'
499
502
  requirements:
500
503
  - none
501
- rubyforge_project:
502
- rubygems_version: 2.7.6
504
+ rubygems_version: 3.0.6
503
505
  signing_key:
504
506
  specification_version: 4
505
507
  summary: R and Ruby in text document