1a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye/*
2a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * Copyright (C) 2011 The Android Open Source Project
3a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye *
4a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * you may not use this file except in compliance with the License.
6a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * You may obtain a copy of the License at
7a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye *
8a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye *      http://www.eclipse.org/org/documents/epl-v10.php
9a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye *
10a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * Unless required by applicable law or agreed to in writing, software
11a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
12a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * See the License for the specific language governing permissions and
14a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye * limitations under the License.
15a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye */
16a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
17a85107f7d763276a5a040cf68e2046ac54202015Tor Norbyepackage com.android.ide.eclipse.adt.internal.lint;
18a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_XML;
204c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
21bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin;
22bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbyeimport com.android.ide.eclipse.adt.AdtUtils;
234c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.IconFactory;
244c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport com.android.tools.lint.detector.api.LintUtils;
25bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbye
26bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbyeimport org.eclipse.core.resources.IFile;
27a85107f7d763276a5a040cf68e2046ac54202015Tor Norbyeimport org.eclipse.core.resources.IProject;
28c1a2b096df38e7b9e6bcac0cc217357f95d0dd3fTor Norbyeimport org.eclipse.core.resources.IResource;
29bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbyeimport org.eclipse.jdt.core.IJavaProject;
304c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jdt.ui.JavaElementLabelProvider;
314c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.action.Action;
324c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.action.ActionContributionItem;
33a85107f7d763276a5a040cf68e2046ac54202015Tor Norbyeimport org.eclipse.jface.action.IAction;
344c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.action.IMenuCreator;
354c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.action.Separator;
36bc32af8dc9e20135c29ba7444ae162761774cdb5Tor Norbyeimport org.eclipse.jface.dialogs.MessageDialog;
374c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.resource.ImageDescriptor;
384c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.jface.viewers.ILabelProvider;
39a85107f7d763276a5a040cf68e2046ac54202015Tor Norbyeimport org.eclipse.jface.viewers.ISelection;
404c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.swt.widgets.Control;
414c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.swt.widgets.Menu;
42229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport org.eclipse.ui.IObjectActionDelegate;
434c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.ui.ISharedImages;
44229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport org.eclipse.ui.IWorkbenchPart;
45229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport org.eclipse.ui.IWorkbenchWindow;
464c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
474c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.ui.PlatformUI;
484c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport org.eclipse.ui.texteditor.ITextEditor;
494c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
504c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport java.util.ArrayList;
514c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyeimport java.util.List;
52a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
534c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye/**
544c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye * Action which runs Lint on the currently projects (and also provides a
554c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye * pulldown menu in the toolbar for selecting specifically which projects to
564c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye * check)
574c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye */
584c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbyepublic class RunLintAction implements IObjectActionDelegate, IMenuCreator,
594c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        IWorkbenchWindowPulldownDelegate {
60a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
61229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    private ISelection mSelection;
624c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    private Menu mMenu;
63a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
64ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
65a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye    public void selectionChanged(IAction action, ISelection selection) {
66a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye        mSelection = selection;
67a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye    }
68a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
69ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
70a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye    public void run(IAction action) {
714c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        List<IProject> projects = getProjects(mSelection, true /* warn */);
72a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
734c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        if (!projects.isEmpty()) {
74d02dad911cea4f854e32cc99e10cdd31ab89a795Tor Norbye            EclipseLintRunner.startLint(projects, null, null, false /*fatalOnly*/, true /*show*/);
75a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye        }
76a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye    }
77a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye
784c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    /** Returns the Android project(s) to apply a lint run to. */
794c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    static List<IProject> getProjects(ISelection selection, boolean warn) {
807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        List<IProject> projects = AdtUtils.getSelectedProjects(selection);
814c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
824c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        if (projects.isEmpty() && warn) {
834c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            MessageDialog.openWarning(AdtPlugin.getDisplay().getActiveShell(), "Lint",
847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye                    "Could not run Lint: Select an Android project first.");
854c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
864c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
874c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        return projects;
88a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye    }
89229581314076be1b6f82fe1efed2bd00da340899Tor Norbye
90ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
91229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    public void setActivePart(IAction action, IWorkbenchPart targetPart) {
92229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    }
93229581314076be1b6f82fe1efed2bd00da340899Tor Norbye
94ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
95229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    public void dispose() {
964c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        if (mMenu != null) {
974c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            mMenu.dispose();
984c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
99229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    }
100229581314076be1b6f82fe1efed2bd00da340899Tor Norbye
101ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
102229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    public void init(IWorkbenchWindow window) {
103229581314076be1b6f82fe1efed2bd00da340899Tor Norbye    }
1044c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1054c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    // ---- IMenuCreator ----
1064c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1074c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    @Override
1084c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    public Menu getMenu(Control parent) {
1094c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        mMenu = new Menu(parent);
1104c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1114c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        IconFactory iconFactory = IconFactory.getInstance();
1124c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ImageDescriptor allIcon = iconFactory.getImageDescriptor("lintrun"); //$NON-NLS-1$
1134c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        LintMenuAction allAction = new LintMenuAction("Check All Projects", allIcon, false, null);
1144c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1154c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        addAction(allAction);
1164c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        addSeparator();
1174c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        IJavaProject[] projects = AdtUtils.getOpenAndroidProjects();
1184c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ILabelProvider provider = new JavaElementLabelProvider(
1194c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                JavaElementLabelProvider.SHOW_DEFAULT);
1204c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        for (IJavaProject project : projects) {
1214c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            IProject p = project.getProject();
1224c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(p));
1234c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            String label = String.format("Check %1$s", p.getName());
1244c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            LintMenuAction projectAction = new LintMenuAction(label, icon, false, p);
1254c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            addAction(projectAction);
1264c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
1274c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1284c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ITextEditor textEditor = AdtUtils.getActiveTextEditor();
1294c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        if (textEditor != null) {
1304c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            IFile file = AdtUtils.getActiveFile();
1314c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            // Currently only supported for XML files
1324c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            if (file != null && LintUtils.endsWith(file.getName(), DOT_XML)) {
1334c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(file));
1344c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                IAction fileAction = new LintMenuAction("Check Current File", icon, false, file);
1354c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1364c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                addSeparator();
1374c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                addAction(fileAction);
1384c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            }
1394c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
1404c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1414c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
1424c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ImageDescriptor clear = images.getImageDescriptor(ISharedImages.IMG_ELCL_REMOVEALL);
143d02dad911cea4f854e32cc99e10cdd31ab89a795Tor Norbye        LintMenuAction clearAction = new LintMenuAction("Clear Lint Warnings", clear, true, null);
1444c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        addSeparator();
1454c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        addAction(clearAction);
1464c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1474c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        return mMenu;
1484c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    }
1494c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1504c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    private void addAction(IAction action) {
1514c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        ActionContributionItem item = new ActionContributionItem(action);
1524c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        item.fill(mMenu, -1);
1534c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    }
1544c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1554c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    private void addSeparator() {
1564c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        new Separator().fill(mMenu, -1);
1574c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    }
1584c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1594c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    @Override
1604c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    public Menu getMenu(Menu parent) {
1614c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        return null;
1624c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    }
1634c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1644c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    /**
1654c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye     * Actions in the pulldown context menu: run lint or clear lint markers on
1664c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye     * the given resource
1674c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye     */
1684c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    private static class LintMenuAction extends Action {
1694c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        private final boolean mClear;
1704c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        private final IResource mResource;
1714c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1724c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        /**
1734c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         * Creates a new context menu action
1744c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         *
1754c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         * @param text the label
1764c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         * @param descriptor the icon
1774c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         * @param clear if true, clear lint markers otherwise check the resource
1784c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         * @param resource the resource to check or clear markers for, where
1794c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         *            null means all projects
1804c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye         */
1814c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        private LintMenuAction(String text, ImageDescriptor descriptor, boolean clear,
1824c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                IResource resource) {
1834c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            super(text, descriptor);
1844c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            mClear = clear;
1854c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            mResource = resource;
1864c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
1874c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye
1884c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        @Override
1894c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        public void run() {
1904c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            List<IResource> resources = new ArrayList<IResource>();
1914c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            if (mResource == null) {
1924c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                // All projects
1934c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                IJavaProject[] open = AdtUtils.getOpenAndroidProjects();
1944c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                for (IJavaProject project : open) {
1954c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                    resources.add(project.getProject());
1964c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                }
1974c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            } else {
1984c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                resources.add(mResource);
1994c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            }
200d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            EclipseLintRunner.cancelCurrentJobs(false);
2014c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            if (mClear) {
2024c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye                EclipseLintClient.clearMarkers(resources);
2034c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            } else {
204d02dad911cea4f854e32cc99e10cdd31ab89a795Tor Norbye                EclipseLintRunner.startLint(resources, null, null, false /*fatalOnly*/,
205d02dad911cea4f854e32cc99e10cdd31ab89a795Tor Norbye                        true /*show*/);
2064c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye            }
2074c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye        }
2084c68f3dc9f10b76f1a32ff9c86587adca385a6d7Tor Norbye    }
209a85107f7d763276a5a040cf68e2046ac54202015Tor Norbye}
210