Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "dp_script.hrc"
31 : : #include "dp_lib_container.h"
32 : : #include "dp_backend.h"
33 : : #include "dp_ucb.h"
34 : : #include "rtl/uri.hxx"
35 : : #include "ucbhelper/content.hxx"
36 : : #include "cppuhelper/exc_hlp.hxx"
37 : : #include "cppuhelper/implbase1.hxx"
38 : : #include "comphelper/servicedecl.hxx"
39 : : #include "svl/inettype.hxx"
40 : : #include "com/sun/star/util/XUpdatable.hpp"
41 : : #include "com/sun/star/script/XLibraryContainer3.hpp"
42 : : #include <com/sun/star/util/XMacroExpander.hpp>
43 : : #include <com/sun/star/uri/XUriReferenceFactory.hpp>
44 : : #include <memory>
45 : : #include "dp_scriptbackenddb.hxx"
46 : :
47 : : using namespace ::dp_misc;
48 : : using namespace ::com::sun::star;
49 : : using namespace ::com::sun::star::uno;
50 : : using namespace ::com::sun::star::ucb;
51 : : using ::rtl::OUString;
52 : : namespace css = ::com::sun::star;
53 : :
54 : : namespace dp_registry {
55 : : namespace backend {
56 : : namespace script {
57 : : namespace {
58 : :
59 : : typedef ::cppu::ImplInheritanceHelper1<
60 : : ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper;
61 : :
62 [ + - ][ + - ]: 380 : class BackendImpl : public t_helper
[ - + ]
63 : : {
64 [ - + ]: 248 : class PackageImpl : public ::dp_registry::backend::Package
65 : : {
66 : : BackendImpl * getMyBackend() const;
67 : :
68 : : const OUString m_scriptURL;
69 : : const OUString m_dialogURL;
70 : : OUString m_dialogName;
71 : :
72 : : // Package
73 : : virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
74 : : ::osl::ResettableMutexGuard & guard,
75 : : ::rtl::Reference<AbortChannel> const & abortChannel,
76 : : Reference<XCommandEnvironment> const & xCmdEnv );
77 : : virtual void processPackage_(
78 : : ::osl::ResettableMutexGuard & guard,
79 : : bool registerPackage,
80 : : bool startup,
81 : : ::rtl::Reference<AbortChannel> const & abortChannel,
82 : : Reference<XCommandEnvironment> const & xCmdEnv );
83 : :
84 : : public:
85 : : PackageImpl(
86 : : ::rtl::Reference<BackendImpl> const & myBackend,
87 : : OUString const & url,
88 : : Reference<XCommandEnvironment> const &xCmdEnv,
89 : : OUString const & scriptURL, OUString const & dialogURL,
90 : : bool bRemoved, OUString const & identifier);
91 : : };
92 : : friend class PackageImpl;
93 : :
94 : : // PackageRegistryBackend
95 : : virtual Reference<deployment::XPackage> bindPackage_(
96 : : OUString const & url, OUString const & mediaType,
97 : : sal_Bool bRemoved, OUString const & identifier,
98 : : Reference<XCommandEnvironment> const & xCmdEnv );
99 : :
100 : : void addDataToDb(OUString const & url);
101 : : bool hasActiveEntry(OUString const & url);
102 : : void revokeEntryFromDb(OUString const & url);
103 : :
104 : : const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo;
105 : : const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo;
106 : : Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
107 : : std::auto_ptr<ScriptBackendDb> m_backendDb;
108 : : public:
109 : : BackendImpl( Sequence<Any> const & args,
110 : : Reference<XComponentContext> const & xComponentContext );
111 : :
112 : : // XUpdatable
113 : : virtual void SAL_CALL update() throw (RuntimeException);
114 : :
115 : : // XPackageRegistry
116 : : virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
117 : : getSupportedPackageTypes() throw (RuntimeException);
118 : : virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
119 : : throw (deployment::DeploymentException,
120 : : uno::RuntimeException);
121 : :
122 : : };
123 : :
124 : : //______________________________________________________________________________
125 : 124 : BackendImpl::PackageImpl::PackageImpl(
126 : : ::rtl::Reference<BackendImpl> const & myBackend,
127 : : OUString const & url,
128 : : Reference<XCommandEnvironment> const &xCmdEnv,
129 : : OUString const & scriptURL, OUString const & dialogURL, bool bRemoved,
130 : : OUString const & identifier)
131 : 124 : : Package( myBackend.get(), url,
132 : : OUString(), OUString(), // will be late-initialized
133 : 248 : !scriptURL.isEmpty() ? myBackend->m_xBasicLibTypeInfo
134 : 0 : : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier),
135 : : m_scriptURL( scriptURL ),
136 [ + - ][ + - ]: 372 : m_dialogURL( dialogURL )
137 : : {
138 : : // name, displayName:
139 [ + - ]: 124 : if (!dialogURL.isEmpty()) {
140 : : m_dialogName = LibraryContainer::get_libname(
141 [ + - ]: 124 : dialogURL, xCmdEnv, myBackend->getComponentContext() );
142 : : }
143 [ + - ]: 124 : if (!scriptURL.isEmpty()) {
144 : : m_name = LibraryContainer::get_libname(
145 [ + - ]: 124 : scriptURL, xCmdEnv, myBackend->getComponentContext() );
146 : : }
147 : : else
148 : 0 : m_name = m_dialogName;
149 : 124 : m_displayName = m_name;
150 : 124 : }
151 : :
152 : : //______________________________________________________________________________
153 : 380 : BackendImpl::BackendImpl(
154 : : Sequence<Any> const & args,
155 : : Reference<XComponentContext> const & xComponentContext )
156 : : : t_helper( args, xComponentContext ),
157 : : m_xBasicLibTypeInfo( new Package::TypeInfo(
158 : : OUSTR("application/"
159 : : "vnd.sun.star.basic-library"),
160 : : OUString() /* no file filter */,
161 : : getResourceString(RID_STR_BASIC_LIB),
162 [ + - ]: 380 : RID_IMG_SCRIPTLIB) ),
163 : : m_xDialogLibTypeInfo( new Package::TypeInfo(
164 : : OUSTR("application/"
165 : : "vnd.sun.star.dialog-library"),
166 : : OUString() /* no file filter */,
167 : : getResourceString(RID_STR_DIALOG_LIB),
168 [ + - ]: 380 : RID_IMG_DIALOGLIB) ),
169 [ + - ][ + - ]: 1140 : m_typeInfos( 2 )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
170 : : {
171 [ + - ][ + - ]: 380 : m_typeInfos[ 0 ] = m_xBasicLibTypeInfo;
172 [ + - ][ + - ]: 380 : m_typeInfos[ 1 ] = m_xDialogLibTypeInfo;
173 : :
174 : : OSL_ASSERT( ! transientMode() );
175 : :
176 [ + - ]: 380 : if (!transientMode())
177 : : {
178 [ + - ][ + - ]: 380 : OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
179 : : m_backendDb.reset(
180 [ + - ][ + - ]: 380 : new ScriptBackendDb(getComponentContext(), dbFile));
181 : : }
182 : :
183 : 380 : }
184 : 62 : void BackendImpl::addDataToDb(OUString const & url)
185 : : {
186 [ + - ]: 62 : if (m_backendDb.get())
187 : 62 : m_backendDb->addEntry(url);
188 : 62 : }
189 : :
190 : 374 : bool BackendImpl::hasActiveEntry(OUString const & url)
191 : : {
192 [ + - ]: 374 : if (m_backendDb.get())
193 : 374 : return m_backendDb->hasActiveEntry(url);
194 : 374 : return false;
195 : : }
196 : :
197 : : // XUpdatable
198 : : //______________________________________________________________________________
199 : 0 : void BackendImpl::update() throw (RuntimeException)
200 : : {
201 : : // Nothing to do here after fixing i70283!?
202 : 0 : }
203 : :
204 : : // XPackageRegistry
205 : : //______________________________________________________________________________
206 : : Sequence< Reference<deployment::XPackageTypeInfo> >
207 : 380 : BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
208 : : {
209 : 380 : return m_typeInfos;
210 : : }
211 : 0 : void BackendImpl::revokeEntryFromDb(OUString const & url)
212 : : {
213 [ # # ]: 0 : if (m_backendDb.get())
214 : 0 : m_backendDb->revokeEntry(url);
215 : 0 : }
216 : :
217 : 0 : void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
218 : : throw (deployment::DeploymentException,
219 : : uno::RuntimeException)
220 : : {
221 [ # # ]: 0 : if (m_backendDb.get())
222 : 0 : m_backendDb->removeEntry(url);
223 : 0 : }
224 : :
225 : : // PackageRegistryBackend
226 : : //______________________________________________________________________________
227 : 537 : Reference<deployment::XPackage> BackendImpl::bindPackage_(
228 : : OUString const & url, OUString const & mediaType_,
229 : : sal_Bool bRemoved, OUString const & identifier,
230 : : Reference<XCommandEnvironment> const & xCmdEnv )
231 : : {
232 : 537 : OUString mediaType( mediaType_ );
233 [ + + ]: 537 : if (mediaType.isEmpty())
234 : : {
235 : : // detect media-type:
236 [ + - ]: 413 : ::ucbhelper::Content ucbContent;
237 [ + - ][ + - ]: 826 : if (create_ucb_content( &ucbContent, url, xCmdEnv ) &&
[ + + ][ + + ]
238 [ + - ]: 413 : ucbContent.isFolder())
239 : : {
240 : : // probe for script.xlb:
241 [ + - - + ]: 818 : if (create_ucb_content(
242 : : 0, makeURL( url, OUSTR("script.xlb") ),
243 [ + - ][ + - ]: 818 : xCmdEnv, false /* no throw */ ))
244 [ # # ]: 0 : mediaType = OUSTR("application/vnd.sun.star.basic-library");
245 : : // probe for dialog.xlb:
246 [ + - - + ]: 818 : else if (create_ucb_content(
247 : : 0, makeURL( url, OUSTR("dialog.xlb") ),
248 [ + - ][ + - ]: 818 : xCmdEnv, false /* no throw */ ))
249 [ # # ]: 0 : mediaType = OUSTR("application/vnd.sun.star.dialog-library");
250 : : }
251 [ + - ]: 413 : if (mediaType.isEmpty())
252 : : throw lang::IllegalArgumentException(
253 [ + - ]: 413 : StrCannotDetectMediaType::get() + url,
254 [ + - ][ + - ]: 826 : static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
[ # # ]
255 : : }
256 : :
257 [ + - ][ + - ]: 124 : String type, subType;
258 [ + - ]: 124 : INetContentTypeParameterList params;
259 [ + - ][ + - ]: 124 : if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
[ + - ][ + - ]
260 : : {
261 [ + - ][ + - ]: 124 : if (type.EqualsIgnoreCaseAscii("application"))
262 : : {
263 [ + - ][ + - ]: 124 : OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) );
264 [ - + ]: 124 : if (! create_ucb_content(
265 [ + - ]: 124 : 0, dialogURL, xCmdEnv, false /* no throw */ )) {
266 : 0 : dialogURL = OUString();
267 : : }
268 : :
269 [ + - ][ + - ]: 124 : if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.basic-library"))
270 : : {
271 [ + - ][ + - ]: 124 : OUString scriptURL( makeURL( url, OUSTR("script.xlb")));
272 [ - + ]: 124 : if (! create_ucb_content(
273 [ + - ]: 124 : 0, scriptURL, xCmdEnv, false /* no throw */ )) {
274 : 0 : scriptURL = OUString();
275 : : }
276 : :
277 : : return new PackageImpl(
278 : : this, url, xCmdEnv, scriptURL,
279 [ + - ][ + - ]: 124 : dialogURL, bRemoved, identifier);
[ + - ]
280 : : }
281 [ # # ]: 0 : else if (subType.EqualsIgnoreCaseAscii(
282 [ # # ]: 0 : "vnd.sun.star.dialog-library")) {
283 : : return new PackageImpl(
284 : : this, url, xCmdEnv,
285 : : OUString() /* no script lib */,
286 : : dialogURL,
287 [ # # ][ # # ]: 0 : bRemoved, identifier);
[ # # ]
288 [ - + ]: 124 : }
289 : : }
290 : : }
291 : : throw lang::IllegalArgumentException(
292 [ # # ]: 0 : StrUnsupportedMediaType::get() + mediaType,
293 : : static_cast<OWeakObject *>(this),
294 [ + - ][ # # ]: 537 : static_cast<sal_Int16>(-1) );
[ # # ][ + - ]
[ + - ]
295 : : }
296 : :
297 : :
298 : : // Package
299 : 498 : BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
300 : : {
301 : 498 : BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
302 [ - + ]: 498 : if (NULL == pBackend)
303 : : {
304 : : //May throw a DisposedException
305 : 0 : check();
306 : : //We should never get here...
307 : : throw RuntimeException(
308 : : OUSTR("Failed to get the BackendImpl"),
309 [ # # ][ # # ]: 0 : static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
[ # # ]
310 : : }
311 : 498 : return pBackend;
312 : : }
313 : :
314 : : beans::Optional< beans::Ambiguous<sal_Bool> >
315 : 312 : BackendImpl::PackageImpl::isRegistered_(
316 : : ::osl::ResettableMutexGuard & /* guard */,
317 : : ::rtl::Reference<AbortChannel> const & /* abortChannel */,
318 : : Reference<XCommandEnvironment> const & /* xCmdEnv */ )
319 : : {
320 [ + - ]: 312 : BackendImpl * that = getMyBackend();
321 [ + - ]: 312 : Reference< deployment::XPackage > xThisPackage( this );
322 : :
323 [ + - ][ + - ]: 312 : bool registered = that->hasActiveEntry(getURL());
324 : : return beans::Optional< beans::Ambiguous<sal_Bool> >(
325 : : true /* IsPresent */,
326 : 312 : beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) );
327 : : }
328 : :
329 : : void
330 : 0 : lcl_maybeRemoveScript(
331 : : bool const bExists,
332 : : OUString const& rName,
333 : : OUString const& rScriptURL,
334 : : Reference<css::script::XLibraryContainer3> const& xScriptLibs)
335 : : {
336 [ # # ][ # # ]: 0 : if (bExists && xScriptLibs.is() && xScriptLibs->hasByName(rName))
[ # # ][ # # ]
337 : : {
338 [ # # ][ # # ]: 0 : const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
339 [ # # ]: 0 : if (sScriptUrl.equals(rScriptURL))
340 [ # # ][ # # ]: 0 : xScriptLibs->removeLibrary(rName);
341 : : }
342 : 0 : }
343 : :
344 : : bool
345 : 0 : lcl_maybeAddScript(
346 : : bool const bExists,
347 : : OUString const& rName,
348 : : OUString const& rScriptURL,
349 : : Reference<css::script::XLibraryContainer3> const& xScriptLibs)
350 : : {
351 [ # # ][ # # ]: 0 : if (bExists && xScriptLibs.is())
[ # # ]
352 : : {
353 : 0 : bool bCanAdd = true;
354 [ # # ]: 0 : if (xScriptLibs->hasByName(rName))
355 : : {
356 [ # # ][ # # ]: 0 : const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
357 : : //We assume here that library names in extensions are unique, which may not be the case
358 : : //ToDo: If the script exist in another extension, then both extensions must have the
359 : : //same id
360 [ # # ][ # # : 0 : if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE"))
# # # # ]
[ # # ]
[ # # # # ]
361 [ # # ][ # # ]: 0 : || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE"))
[ # # ]
362 [ # # ][ # # ]: 0 : || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")))
[ # # ]
363 : : {
364 [ # # ][ # # ]: 0 : xScriptLibs->removeLibrary(rName);
365 : 0 : bCanAdd = true;
366 : : }
367 : : else
368 : : {
369 : 0 : bCanAdd = false;
370 : 0 : }
371 : : }
372 : :
373 [ # # ]: 0 : if (bCanAdd)
374 : : {
375 : 0 : xScriptLibs->createLibraryLink(rName, rScriptURL, false);
376 : 0 : return xScriptLibs->hasByName(rName);
377 : : }
378 : : }
379 : :
380 : 0 : return false;
381 : : }
382 : :
383 : 62 : void BackendImpl::PackageImpl::processPackage_(
384 : : ::osl::ResettableMutexGuard & /* guard */,
385 : : bool doRegisterPackage,
386 : : bool startup,
387 : : ::rtl::Reference<AbortChannel> const & /* abortChannel */,
388 : : Reference<XCommandEnvironment> const & /* xCmdEnv */ )
389 : : {
390 [ + - ]: 62 : BackendImpl * that = getMyBackend();
391 : :
392 [ + - ]: 62 : Reference< deployment::XPackage > xThisPackage( this );
393 : 62 : Reference<XComponentContext> const & xComponentContext = that->getComponentContext();
394 : :
395 : 62 : bool bScript = !m_scriptURL.isEmpty();
396 : 62 : Reference<css::script::XLibraryContainer3> xScriptLibs;
397 : :
398 : 62 : bool bDialog = !m_dialogURL.isEmpty();
399 : 62 : Reference<css::script::XLibraryContainer3> xDialogLibs;
400 : :
401 [ # # ][ # # ]: 62 : bool bRunning = !startup && office_is_running();
[ - + ]
402 [ - + ]: 62 : if( bRunning )
403 : : {
404 [ # # ]: 0 : if( bScript )
405 : : {
406 : : xScriptLibs.set(
407 [ # # ][ # # ]: 0 : xComponentContext->getServiceManager()->createInstanceWithContext(
[ # # ]
408 : : OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"),
409 [ # # ][ # # ]: 0 : xComponentContext ), UNO_QUERY_THROW );
[ # # ]
410 : : }
411 : :
412 [ # # ]: 0 : if( bDialog )
413 : : {
414 : : xDialogLibs.set(
415 [ # # ][ # # ]: 0 : xComponentContext->getServiceManager()->createInstanceWithContext(
[ # # ]
416 : : OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"),
417 [ # # ][ # # ]: 0 : xComponentContext ), UNO_QUERY_THROW );
[ # # ]
418 : : }
419 : : }
420 [ + - ][ + - ]: 62 : bool bRegistered = getMyBackend()->hasActiveEntry(getURL());
[ + - ]
421 [ - + ]: 62 : if( !doRegisterPackage )
422 : : {
423 : : //We cannot just call removeLibrary(name) because this could remove a
424 : : //script which was added by an extension in a different repository. For
425 : : //example, extension foo is contained in the bundled repository and then
426 : : //the user adds it it to the user repository. The extension manager will
427 : : //then register the new script and revoke the script from the bundled
428 : : //extension. removeLibrary(name) would now remove the script from the
429 : : //user repository. That is, the script of the newly added user extension does
430 : : //not work anymore. Therefore we must check if the currently active
431 : : //script comes in fact from the currently processed extension.
432 : :
433 [ # # ]: 0 : if (bRegistered)
434 : : {
435 : : //we also prevent and live deployment at startup
436 [ # # ][ # # ]: 0 : if (!isRemoved() && !startup)
[ # # ][ # # ]
437 : : {
438 [ # # ]: 0 : lcl_maybeRemoveScript(bScript, m_name, m_scriptURL, xScriptLibs);
439 [ # # ]: 0 : lcl_maybeRemoveScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
440 : : }
441 [ # # ][ # # ]: 0 : getMyBackend()->revokeEntryFromDb(getURL());
[ # # ]
442 : : return;
443 : : }
444 : : }
445 [ - + ]: 62 : if (bRegistered)
446 : : return; // Already registered
447 : :
448 : : // Update LibraryContainer
449 : 62 : bool bScriptSuccess = false;
450 : 62 : bool bDialogSuccess = false;
451 [ - + ]: 62 : if (!startup)
452 : : {
453 : : //If there is a bundled extension, and the user installes the same extension
454 : : //then the script from the bundled extension must be removed. If this does not work
455 : : //then live deployment does not work for scripts.
456 [ # # ]: 0 : bScriptSuccess = lcl_maybeAddScript(bScript, m_name, m_scriptURL, xScriptLibs);
457 [ # # ]: 0 : bDialogSuccess = lcl_maybeAddScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
458 : : }
459 [ - + ][ # # ]: 62 : bool bSuccess = bScript || bDialog; // Something must have happened
460 [ - + ]: 62 : if( bRunning )
461 [ # # ][ # # ]: 0 : if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) )
[ # # ][ # # ]
462 : 0 : bSuccess = false;
463 : :
464 [ + - ]: 62 : if (bSuccess)
465 [ + - ][ + - ]: 62 : getMyBackend()->addDataToDb(getURL());
[ + - ][ - + ]
[ - + ][ + - ]
466 : : }
467 : :
468 : : } // anon namespace
469 : :
470 : : namespace sdecl = comphelper::service_decl;
471 : 124 : sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
472 : 124 : extern sdecl::ServiceDecl const serviceDecl(
473 : : serviceBI,
474 : : "com.sun.star.comp.deployment.script.PackageRegistryBackend",
475 : : BACKEND_SERVICE_NAME );
476 : :
477 : : } // namespace script
478 : : } // namespace backend
479 [ + - ][ + - ]: 372 : } // namespace dp_registry
480 : :
481 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|