1eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/*
2eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Copyright (C) 2016 The Android Open Source Project
3eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
4eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Licensed under the Apache License, Version 2.0 (the "License");
5eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * you may not use this file except in compliance with the License.
6eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * You may obtain a copy of the License at
7eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
8eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *      http://www.apache.org/licenses/LICENSE-2.0
9eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
10eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Unless required by applicable law or agreed to in writing, software
11eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * distributed under the License is distributed on an "AS IS" BASIS,
12eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * See the License for the specific language governing permissions and
14eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * limitations under the License.
15eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */
16eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
17eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadpackage com.android.server.om;
18eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
19eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.annotation.NonNull;
20eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.annotation.Nullable;
21eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.om.IOverlayManager;
22eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.om.OverlayInfo;
23eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.RemoteException;
24eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.ShellCommand;
25eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.UserHandle;
26eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
27eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.PrintWriter;
28eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.util.List;
29eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.util.Map;
30eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
31eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/**
32eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Implementation of 'cmd overlay' commands.
33eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
34eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * This class provides an interface to the OverlayManagerService via adb.
35eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Intended only for manual debugging. Execute 'adb exec-out cmd overlay help'
36eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * for a list of available commands.
37eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */
38eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadfinal class OverlayManagerShellCommand extends ShellCommand {
39eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private final IOverlayManager mInterface;
40eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
41eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    OverlayManagerShellCommand(@NonNull final IOverlayManager iom) {
42eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        mInterface = iom;
43eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
44eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
45eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    @Override
46eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    public int onCommand(@Nullable final String cmd) {
47eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        if (cmd == null) {
48eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return handleDefaultCommands(cmd);
49eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
50eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter err = getErrPrintWriter();
51eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        try {
52eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            switch (cmd) {
53eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "list":
54eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return runList();
55eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "enable":
56eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return runEnableDisable(true);
57eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "disable":
58eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return runEnableDisable(false);
59eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "set-priority":
60eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return runSetPriority();
61eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                default:
62eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return handleDefaultCommands(cmd);
63eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            }
64eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } catch (IllegalArgumentException e) {
65eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            err.println("Error: " + e.getMessage());
66eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } catch (RemoteException e) {
67eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            err.println("Remote exception: " + e);
68eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
69eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return -1;
70eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
71eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
72eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    @Override
73eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    public void onHelp() {
74eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter out = getOutPrintWriter();
75eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("Overlay manager (overlay) commands:");
76eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  help");
77eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Print this help text.");
78eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
79eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Print debugging information about the overlay manager.");
80eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  list [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
81eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Print information about target and overlay packages.");
82eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Overlay packages are printed in priority order. With optional");
83eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    parameters PACKAGEs, limit output to the specified packages");
84eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    but include more information about each package.");
85eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  enable [--user USER_ID] PACKAGE");
86eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Enable overlay package PACKAGE.");
87eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  disable [--user USER_ID] PACKAGE");
88eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Disable overlay package PACKAGE.");
89eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("  set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest");
90eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    Change the priority of the overlay PACKAGE to be just higher than");
91eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    the priority of PACKAGE_PARENT If PARENT is the special keyword");
92eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    'lowest', change priority of PACKAGE to the lowest priority.");
93eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    If PARENT is the special keyword 'highest', change priority of");
94eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        out.println("    PACKAGE to the highest priority.");
95eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
96eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
97eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private int runList() throws RemoteException {
98eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter out = getOutPrintWriter();
99eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter err = getErrPrintWriter();
100eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
101eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        int userId = UserHandle.USER_SYSTEM;
102eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        String opt;
103eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        while ((opt = getNextOption()) != null) {
104eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            switch (opt) {
105eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "--user":
106eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    userId = UserHandle.parseUserArg(getNextArgRequired());
107eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    break;
108eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                default:
109eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    err.println("Error: Unknown option: " + opt);
110eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return 1;
111eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            }
112eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
113eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
114eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId);
115eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        for (final String targetPackageName : allOverlays.keySet()) {
116eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            out.println(targetPackageName);
117eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName);
118eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            final int N = overlaysForTarget.size();
119eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            for (int i = 0; i < N; i++) {
120eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                final OverlayInfo oi = overlaysForTarget.get(i);
121eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                String status;
122eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                switch (oi.state) {
123eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    case OverlayInfo.STATE_ENABLED:
124eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        status = "[x]";
125eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        break;
126eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    case OverlayInfo.STATE_DISABLED:
127eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        status = "[ ]";
128eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        break;
129eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    default:
130eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        status = "---";
131eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                        break;
132eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                }
133eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                out.println(String.format("%s %s", status, oi.packageName));
134eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            }
135eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            out.println();
136eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
137eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return 0;
138eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
139eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
140eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private int runEnableDisable(final boolean enable) throws RemoteException {
141eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter err = getErrPrintWriter();
142eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
143eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        int userId = UserHandle.USER_SYSTEM;
144eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        String opt;
145eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        while ((opt = getNextOption()) != null) {
146eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            switch (opt) {
147eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "--user":
148eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    userId = UserHandle.parseUserArg(getNextArgRequired());
149eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    break;
150eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                default:
151eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    err.println("Error: Unknown option: " + opt);
152eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return 1;
153eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            }
154eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
155eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
156eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final String packageName = getNextArgRequired();
157eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1;
158eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
159eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
160eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private int runSetPriority() throws RemoteException {
161eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final PrintWriter err = getErrPrintWriter();
162eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
163eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        int userId = UserHandle.USER_SYSTEM;
164eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        String opt;
165eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        while ((opt = getNextOption()) != null) {
166eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            switch (opt) {
167eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                case "--user":
168eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    userId = UserHandle.parseUserArg(getNextArgRequired());
169eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    break;
170eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                default:
171eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    err.println("Error: Unknown option: " + opt);
172eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    return 1;
173eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            }
174eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
175eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
176eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final String packageName = getNextArgRequired();
177eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final String newParentPackageName = getNextArgRequired();
178eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
179eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        if ("highest".equals(newParentPackageName)) {
180eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return mInterface.setHighestPriority(packageName, userId) ? 0 : 1;
181eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } else if ("lowest".equals(newParentPackageName)) {
182eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return mInterface.setLowestPriority(packageName, userId) ? 0 : 1;
183eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } else {
184eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return mInterface.setPriority(packageName, newParentPackageName, userId) ? 0 : 1;
185eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
186eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
187eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad}
188